mirror of
https://github.com/nomic-ai/gpt4all.git
synced 2025-06-22 21:48:23 +00:00
WIP (fixing compile errors)
This commit is contained in:
parent
f7cd880f96
commit
bcbbe5194a
@ -245,6 +245,7 @@ qt_add_executable(chat
|
|||||||
src/llmodel_ollama.cpp src/llmodel_ollama.h
|
src/llmodel_ollama.cpp src/llmodel_ollama.h
|
||||||
src/llmodel_openai.cpp src/llmodel_openai.h
|
src/llmodel_openai.cpp src/llmodel_openai.h
|
||||||
src/llmodel_provider.cpp src/llmodel_provider.h
|
src/llmodel_provider.cpp src/llmodel_provider.h
|
||||||
|
src/llmodel_provider_builtins.cpp
|
||||||
src/localdocs.cpp src/localdocs.h
|
src/localdocs.cpp src/localdocs.h
|
||||||
src/localdocsmodel.cpp src/localdocsmodel.h
|
src/localdocsmodel.cpp src/localdocsmodel.h
|
||||||
src/logger.cpp src/logger.h
|
src/logger.cpp src/logger.h
|
||||||
|
@ -330,10 +330,8 @@ void ChatLLM::trySwitchContextOfLoadedModel(const ModelInfo &modelInfo)
|
|||||||
emit trySwitchContextOfLoadedModelCompleted(0);
|
emit trySwitchContextOfLoadedModelCompleted(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: always call with a resource guard held since this didn't previously use coroutines
|
|
||||||
auto ChatLLM::loadModel(const ModelInfo &modelInfo) -> QCoro::Task<bool>
|
auto ChatLLM::loadModel(const ModelInfo &modelInfo) -> QCoro::Task<bool>
|
||||||
{
|
{
|
||||||
// TODO: get the description from somewhere
|
|
||||||
bool alreadyAcquired = isModelLoaded();
|
bool alreadyAcquired = isModelLoaded();
|
||||||
if (alreadyAcquired && *modelInfo.modelDesc() == *m_modelInfo.modelDesc()) {
|
if (alreadyAcquired && *modelInfo.modelDesc() == *m_modelInfo.modelDesc()) {
|
||||||
// already acquired -> keep it
|
// already acquired -> keep it
|
||||||
|
@ -19,7 +19,6 @@ struct ChatResponseMetadata {
|
|||||||
int nResponseTokens;
|
int nResponseTokens;
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO: implement two of these; one based on Ollama (TBD) and the other based on OpenAI (chatapi.h)
|
|
||||||
class ChatLLMInstance {
|
class ChatLLMInstance {
|
||||||
public:
|
public:
|
||||||
virtual ~ChatLLMInstance() noexcept = 0;
|
virtual ~ChatLLMInstance() noexcept = 0;
|
||||||
|
@ -15,12 +15,14 @@ namespace gpt4all::ui {
|
|||||||
|
|
||||||
class ChatLLMInstance;
|
class ChatLLMInstance;
|
||||||
|
|
||||||
// TODO: implement shared_from_this guidance for restricted construction
|
|
||||||
class ModelDescription : public std::enable_shared_from_this<ModelDescription> {
|
class ModelDescription : public std::enable_shared_from_this<ModelDescription> {
|
||||||
Q_GADGET
|
Q_GADGET
|
||||||
Q_PROPERTY(const ModelProvider *provider READ provider CONSTANT)
|
Q_PROPERTY(const ModelProvider *provider READ provider CONSTANT)
|
||||||
Q_PROPERTY(QVariant key READ key CONSTANT)
|
Q_PROPERTY(QVariant key READ key CONSTANT)
|
||||||
|
|
||||||
|
protected:
|
||||||
|
struct protected_t { explicit protected_t() = default; };
|
||||||
|
|
||||||
public:
|
public:
|
||||||
virtual ~ModelDescription() noexcept = 0;
|
virtual ~ModelDescription() noexcept = 0;
|
||||||
|
|
||||||
|
@ -34,10 +34,13 @@ auto OllamaProvider::makeGenerationParams(const QMap<GenerationParam, QVariant>
|
|||||||
{ return new OllamaGenerationParams(values); }
|
{ return new OllamaGenerationParams(values); }
|
||||||
|
|
||||||
/// load
|
/// load
|
||||||
OllamaProviderCustom::OllamaProviderCustom(std::shared_ptr<ProviderStore> store, QUuid id)
|
OllamaProviderCustom::OllamaProviderCustom(std::shared_ptr<ProviderStore> store, QUuid id, QString name, QUrl baseUrl)
|
||||||
: ModelProvider(std::move(id))
|
: ModelProvider (std::move(id), std::move(name), std::move(baseUrl))
|
||||||
, ModelProviderCustom(std::move(store))
|
, ModelProviderCustom(std::move(store))
|
||||||
{ load(); }
|
{
|
||||||
|
if (auto res = m_store->acquire(m_id); !res)
|
||||||
|
res.error().raise();
|
||||||
|
}
|
||||||
|
|
||||||
/// create
|
/// create
|
||||||
OllamaProviderCustom::OllamaProviderCustom(std::shared_ptr<ProviderStore> store, QString name, QUrl baseUrl)
|
OllamaProviderCustom::OllamaProviderCustom(std::shared_ptr<ProviderStore> store, QString name, QUrl baseUrl)
|
||||||
@ -50,7 +53,19 @@ OllamaProviderCustom::OllamaProviderCustom(std::shared_ptr<ProviderStore> store,
|
|||||||
m_id = (*data)->id;
|
m_id = (*data)->id;
|
||||||
}
|
}
|
||||||
|
|
||||||
OllamaModelDescription::OllamaModelDescription(std::shared_ptr<const OllamaProvider> provider, QByteArray modelHash)
|
auto OllamaProviderCustom::asData() -> ModelProviderData
|
||||||
|
{
|
||||||
|
return {
|
||||||
|
.id = m_id,
|
||||||
|
.builtin = false,
|
||||||
|
.type = ProviderType::ollama,
|
||||||
|
.custom_details = CustomProviderDetails { m_name, m_baseUrl },
|
||||||
|
.provider_details = {},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
OllamaModelDescription::OllamaModelDescription(protected_t, std::shared_ptr<const OllamaProvider> provider,
|
||||||
|
QByteArray modelHash)
|
||||||
: m_provider (std::move(provider ))
|
: m_provider (std::move(provider ))
|
||||||
, m_modelHash(std::move(modelHash))
|
, m_modelHash(std::move(modelHash))
|
||||||
{}
|
{}
|
||||||
|
@ -50,8 +50,10 @@ public:
|
|||||||
auto makeGenerationParams(const QMap<GenerationParam, QVariant> &values) const -> OllamaGenerationParams * override;
|
auto makeGenerationParams(const QMap<GenerationParam, QVariant> &values) const -> OllamaGenerationParams * override;
|
||||||
};
|
};
|
||||||
|
|
||||||
class OllamaProviderBuiltin : public OllamaProvider, public ModelProviderBuiltin {
|
class OllamaProviderBuiltin : public OllamaProvider {
|
||||||
Q_GADGET
|
Q_GADGET
|
||||||
|
Q_PROPERTY(QString name READ name CONSTANT)
|
||||||
|
Q_PROPERTY(QUrl baseUrl READ baseUrl CONSTANT)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/// Create a new built-in Ollama provider (transient).
|
/// Create a new built-in Ollama provider (transient).
|
||||||
@ -64,18 +66,17 @@ class OllamaProviderCustom final : public OllamaProvider, public ModelProviderCu
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
/// Load an existing OllamaProvider from disk.
|
/// Load an existing OllamaProvider from disk.
|
||||||
explicit OllamaProviderCustom(std::shared_ptr<ProviderStore> store, QUuid id);
|
explicit OllamaProviderCustom(ProviderStore *store, QUuid id, QString name, QUrl baseUrl);
|
||||||
|
|
||||||
/// Create a new OllamaProvider on disk.
|
/// Create a new OllamaProvider on disk.
|
||||||
explicit OllamaProviderCustom(std::shared_ptr<ProviderStore> store, QString name, QUrl baseUrl);
|
explicit OllamaProviderCustom(ProviderStore *store, QString name, QUrl baseUrl);
|
||||||
|
|
||||||
Q_SIGNALS:
|
Q_SIGNALS:
|
||||||
void nameChanged (const QString &value);
|
void nameChanged (const QString &value);
|
||||||
void baseUrlChanged(const QUrl &value);
|
void baseUrlChanged(const QUrl &value);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
auto asData() -> ModelProviderData override
|
auto asData() -> ModelProviderData override;
|
||||||
{ return { m_id, ProviderType::ollama, m_name, m_baseUrl, {} }; }
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class OllamaModelDescription : public ModelDescription {
|
class OllamaModelDescription : public ModelDescription {
|
||||||
@ -83,7 +84,11 @@ class OllamaModelDescription : public ModelDescription {
|
|||||||
Q_PROPERTY(QByteArray modelHash READ modelHash CONSTANT)
|
Q_PROPERTY(QByteArray modelHash READ modelHash CONSTANT)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit OllamaModelDescription(std::shared_ptr<const OllamaProvider> provider, QByteArray modelHash);
|
explicit OllamaModelDescription(protected_t, std::shared_ptr<const OllamaProvider> provider, QByteArray modelHash);
|
||||||
|
|
||||||
|
static auto create(std::shared_ptr<const OllamaProvider> provider, QByteArray modelHash)
|
||||||
|
-> std::shared_ptr<OllamaModelDescription>
|
||||||
|
{ return std::make_shared<OllamaModelDescription>(protected_t(), std::move(provider), std::move(modelHash)); }
|
||||||
|
|
||||||
// getters
|
// getters
|
||||||
[[nodiscard]] auto provider () const -> const OllamaProvider * override { return m_provider.get(); }
|
[[nodiscard]] auto provider () const -> const OllamaProvider * override { return m_provider.get(); }
|
||||||
|
@ -96,23 +96,38 @@ auto OpenaiProvider::makeGenerationParams(const QMap<GenerationParam, QVariant>
|
|||||||
-> OpenaiGenerationParams *
|
-> OpenaiGenerationParams *
|
||||||
{ return new OpenaiGenerationParams(values); }
|
{ return new OpenaiGenerationParams(values); }
|
||||||
|
|
||||||
OpenaiProviderBuiltin::OpenaiProviderBuiltin(QUuid id, QString name, QUrl baseUrl, QString apiKey)
|
OpenaiProviderBuiltin::OpenaiProviderBuiltin(ProviderStore *store, QUuid id, QString name, QUrl baseUrl)
|
||||||
: ModelProvider(std::move(id), std::move(name), std::move(baseUrl))
|
: ModelProvider(std::move(id), std::move(name), std::move(baseUrl))
|
||||||
, OpenaiProvider(std::move(apiKey))
|
, ModelProviderMutable(store)
|
||||||
{}
|
|
||||||
|
|
||||||
/// load
|
|
||||||
OpenaiProviderCustom::OpenaiProviderCustom(std::shared_ptr<ProviderStore> store, QUuid id)
|
|
||||||
: ModelProvider(std::move(id))
|
|
||||||
, ModelProviderCustom(std::move(store))
|
|
||||||
{
|
{
|
||||||
auto &details = load();
|
auto res = m_store->acquire(m_id);
|
||||||
m_apiKey = std::get<OpenaiProviderDetails>(details).api_key;
|
if (!res)
|
||||||
|
res.error().raise();
|
||||||
|
if (auto maybeData = *res) {
|
||||||
|
auto &details = (*maybeData)->openai_details.value();
|
||||||
|
m_apiKey = details.api_key;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto OpenaiProviderBuiltin::asData() -> ModelProviderData
|
||||||
|
{
|
||||||
|
return {
|
||||||
|
.id = m_id,
|
||||||
|
.type = ProviderType::openai,
|
||||||
|
.custom_details = {},
|
||||||
|
.openai_details = OpenaiProviderDetails { m_apiKey },
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// load
|
||||||
|
OpenaiProviderCustom::OpenaiProviderCustom(ProviderStore *store, QUuid id, QString name, QUrl baseUrl, QString apiKey)
|
||||||
|
: ModelProvider(std::move(id), std::move(name), std::move(baseUrl))
|
||||||
|
, OpenaiProvider(std::move(apiKey))
|
||||||
|
, ModelProviderCustom(store)
|
||||||
|
{}
|
||||||
|
|
||||||
/// create
|
/// create
|
||||||
OpenaiProviderCustom::OpenaiProviderCustom(std::shared_ptr<ProviderStore> store, QString name, QUrl baseUrl,
|
OpenaiProviderCustom::OpenaiProviderCustom(ProviderStore *store, QString name, QUrl baseUrl, QString apiKey)
|
||||||
QString apiKey)
|
|
||||||
: ModelProvider(std::move(name), std::move(baseUrl))
|
: ModelProvider(std::move(name), std::move(baseUrl))
|
||||||
, ModelProviderCustom(std::move(store))
|
, ModelProviderCustom(std::move(store))
|
||||||
, OpenaiProvider(std::move(apiKey))
|
, OpenaiProvider(std::move(apiKey))
|
||||||
@ -123,7 +138,18 @@ OpenaiProviderCustom::OpenaiProviderCustom(std::shared_ptr<ProviderStore> store,
|
|||||||
m_id = (*data)->id;
|
m_id = (*data)->id;
|
||||||
}
|
}
|
||||||
|
|
||||||
OpenaiModelDescription::OpenaiModelDescription(std::shared_ptr<const OpenaiProvider> provider, QString modelName)
|
auto OpenaiProviderCustom::asData() -> ModelProviderData
|
||||||
|
{
|
||||||
|
return {
|
||||||
|
.id = m_id,
|
||||||
|
.type = ProviderType::openai,
|
||||||
|
.custom_details = CustomProviderDetails { m_name, m_baseUrl },
|
||||||
|
.openai_details = OpenaiProviderDetails { m_apiKey },
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
OpenaiModelDescription::OpenaiModelDescription(protected_t, std::shared_ptr<const OpenaiProvider> provider,
|
||||||
|
QString modelName)
|
||||||
: m_provider (std::move(provider ))
|
: m_provider (std::move(provider ))
|
||||||
, m_modelName(std::move(modelName))
|
, m_modelName(std::move(modelName))
|
||||||
{}
|
{}
|
||||||
|
@ -42,12 +42,13 @@ protected:
|
|||||||
|
|
||||||
class OpenaiProvider : public QObject, public virtual ModelProvider {
|
class OpenaiProvider : public QObject, public virtual ModelProvider {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
Q_PROPERTY(QString apiKey READ apiKey WRITE setApiKey NOTIFY apiKeyChanged)
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
explicit OpenaiProvider() = default; // custom
|
explicit OpenaiProvider() = default;
|
||||||
explicit OpenaiProvider(QString apiKey) // built-in
|
explicit OpenaiProvider(QString apiKey)
|
||||||
: m_apiKey(std::move(apiKey))
|
: m_apiKey(std::move(apiKey)) {}
|
||||||
{}
|
|
||||||
public:
|
public:
|
||||||
~OpenaiProvider() noexcept override = 0;
|
~OpenaiProvider() noexcept override = 0;
|
||||||
|
|
||||||
@ -56,6 +57,8 @@ public:
|
|||||||
|
|
||||||
[[nodiscard]] const QString &apiKey() const { return m_apiKey; }
|
[[nodiscard]] const QString &apiKey() const { return m_apiKey; }
|
||||||
|
|
||||||
|
virtual void setApiKey(QString value) = 0;
|
||||||
|
|
||||||
auto supportedGenerationParams() const -> QSet<GenerationParam> override;
|
auto supportedGenerationParams() const -> QSet<GenerationParam> override;
|
||||||
auto makeGenerationParams(const QMap<GenerationParam, QVariant> &values) const -> OpenaiGenerationParams * override;
|
auto makeGenerationParams(const QMap<GenerationParam, QVariant> &values) const -> OpenaiGenerationParams * override;
|
||||||
|
|
||||||
@ -63,28 +66,32 @@ protected:
|
|||||||
QString m_apiKey;
|
QString m_apiKey;
|
||||||
};
|
};
|
||||||
|
|
||||||
class OpenaiProviderBuiltin : public OpenaiProvider, public ModelProviderBuiltin {
|
class OpenaiProviderBuiltin : public OpenaiProvider, private ModelProviderMutable {
|
||||||
Q_GADGET
|
Q_GADGET
|
||||||
Q_PROPERTY(QString apiKey READ apiKey CONSTANT)
|
Q_PROPERTY(QString name READ name CONSTANT)
|
||||||
|
Q_PROPERTY(QUrl baseUrl READ baseUrl CONSTANT)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/// Create a new built-in OpenAI provider (transient).
|
/// Create a new built-in OpenAI provider, loading its API key from disk if known.
|
||||||
explicit OpenaiProviderBuiltin(QUuid id, QString name, QUrl baseUrl, QString apiKey);
|
explicit OpenaiProviderBuiltin(ProviderStore *store, QUuid id, QString name, QUrl baseUrl);
|
||||||
|
|
||||||
|
void setApiKey(QString value) override { setMemberProp<QString>(&OpenaiProviderBuiltin::m_apiKey, "apiKey", std::move(value)); }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
auto asData() -> ModelProviderData override;
|
||||||
};
|
};
|
||||||
|
|
||||||
class OpenaiProviderCustom final : public OpenaiProvider, public ModelProviderCustom {
|
class OpenaiProviderCustom final : public OpenaiProvider, public ModelProviderCustom {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
Q_PROPERTY(QString apiKey READ apiKey WRITE setApiKey NOTIFY apiKeyChanged)
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/// Load an existing OpenaiProvider from disk.
|
/// Load an existing OpenaiProvider from disk.
|
||||||
explicit OpenaiProviderCustom(std::shared_ptr<ProviderStore> store, QUuid id);
|
explicit OpenaiProviderCustom(ProviderStore *store, QUuid id, QString name, QUrl baseUrl, QString apiKey);
|
||||||
|
|
||||||
/// Create a new OpenaiProvider on disk.
|
/// Create a new OpenaiProvider on disk.
|
||||||
explicit OpenaiProviderCustom(std::shared_ptr<ProviderStore> store, QString name, QUrl baseUrl, QString apiKey);
|
explicit OpenaiProviderCustom(ProviderStore *store, QString name, QUrl baseUrl, QString apiKey);
|
||||||
|
|
||||||
void setApiKey(QString value) { setMemberProp<QString>(&OpenaiProviderCustom::m_apiKey, "apiKey", std::move(value)); }
|
void setApiKey(QString value) override { setMemberProp<QString>(&OpenaiProviderCustom::m_apiKey, "apiKey", std::move(value)); }
|
||||||
|
|
||||||
Q_SIGNALS:
|
Q_SIGNALS:
|
||||||
void nameChanged (const QString &value);
|
void nameChanged (const QString &value);
|
||||||
@ -92,8 +99,7 @@ Q_SIGNALS:
|
|||||||
void apiKeyChanged (const QString &value);
|
void apiKeyChanged (const QString &value);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
auto asData() -> ModelProviderData override
|
auto asData() -> ModelProviderData override;
|
||||||
{ return { m_id, ProviderType::openai, m_name, m_baseUrl, OpenaiProviderDetails { m_apiKey } }; }
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class OpenaiModelDescription : public ModelDescription {
|
class OpenaiModelDescription : public ModelDescription {
|
||||||
@ -101,7 +107,11 @@ class OpenaiModelDescription : public ModelDescription {
|
|||||||
Q_PROPERTY(QString modelName READ modelName CONSTANT)
|
Q_PROPERTY(QString modelName READ modelName CONSTANT)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit OpenaiModelDescription(std::shared_ptr<const OpenaiProvider> provider, QString modelName);
|
explicit OpenaiModelDescription(protected_t, std::shared_ptr<const OpenaiProvider> provider, QString modelName);
|
||||||
|
|
||||||
|
static auto create(std::shared_ptr<const OpenaiProvider> provider, QByteArray modelHash)
|
||||||
|
-> std::shared_ptr<OpenaiModelDescription>
|
||||||
|
{ return std::make_shared<OpenaiModelDescription>(protected_t(), std::move(provider), std::move(modelHash)); }
|
||||||
|
|
||||||
// getters
|
// getters
|
||||||
[[nodiscard]] auto provider () const -> const OpenaiProvider * override { return m_provider.get(); }
|
[[nodiscard]] auto provider () const -> const OpenaiProvider * override { return m_provider.get(); }
|
||||||
|
@ -1,5 +1,8 @@
|
|||||||
#include "llmodel_provider.h"
|
#include "llmodel_provider.h"
|
||||||
|
|
||||||
|
#include "llmodel_ollama.h"
|
||||||
|
#include "llmodel_openai.h"
|
||||||
|
|
||||||
#include "mysettings.h"
|
#include "mysettings.h"
|
||||||
|
|
||||||
#include <fmt/format.h>
|
#include <fmt/format.h>
|
||||||
@ -42,61 +45,91 @@ QVariant GenerationParams::tryParseValue(QMap<GenerationParam, QVariant> &values
|
|||||||
|
|
||||||
ModelProvider::~ModelProvider() noexcept = default;
|
ModelProvider::~ModelProvider() noexcept = default;
|
||||||
|
|
||||||
ModelProviderCustom::~ModelProviderCustom() noexcept
|
ModelProviderMutable::~ModelProviderMutable() noexcept
|
||||||
{
|
{
|
||||||
if (auto res = m_store->release(m_id); !res)
|
if (auto res = m_store->release(m_id); !res)
|
||||||
res.error().raise(); // should not happen - will terminate program
|
res.error().raise(); // should not happen - will terminate program
|
||||||
}
|
}
|
||||||
|
|
||||||
auto ModelProviderCustom::load() -> const ModelProviderData::Details &
|
ProviderRegistry::ProviderRegistry(PathSet paths)
|
||||||
{
|
: m_customStore (std::move(paths.custom ))
|
||||||
auto data = m_store->acquire(m_id);
|
, m_builtinStore(std::move(paths.builtin))
|
||||||
if (!data)
|
|
||||||
data.error().raise();
|
|
||||||
m_name = (*data)->name;
|
|
||||||
m_baseUrl = (*data)->base_url;
|
|
||||||
return (*data)->details;
|
|
||||||
}
|
|
||||||
|
|
||||||
ProviderRegistry::ProviderRegistry(fs::path path)
|
|
||||||
: m_store(std::move(path))
|
|
||||||
{
|
{
|
||||||
auto *mysettings = MySettings::globalInstance();
|
auto *mysettings = MySettings::globalInstance();
|
||||||
connect(mysettings, &MySettings::modelPathChanged, this, &ProviderRegistry::onModelPathChanged);
|
connect(mysettings, &MySettings::modelPathChanged, this, &ProviderRegistry::onModelPathChanged);
|
||||||
|
load();
|
||||||
}
|
}
|
||||||
|
|
||||||
Q_INVOKABLE void ProviderRegistry::registerBuiltinProvider(ModelProviderBuiltin *provider)
|
void ProviderRegistry::load()
|
||||||
{
|
{
|
||||||
auto [_, unique] = m_providers.emplace(provider->id(), provider->asQObject());
|
for (auto &p : s_builtinProviders) { // (not all builtin providers are stored)
|
||||||
|
auto provider = std::make_shared<OpenaiProviderBuiltin>(m_builtinStore, p.id, p.name, p.base_url);
|
||||||
|
auto [_, unique] = m_providers.emplace(p.id, std::move(provider));
|
||||||
if (!unique)
|
if (!unique)
|
||||||
qWarning() << "ignoring duplicate provider:" << provider->id();
|
throw std::logic_error(fmt::format("duplicate builtin provider id: {}", p.id));
|
||||||
|
}
|
||||||
|
for (auto &p : m_customStore.list()) { // disk is source of truth for custom providers
|
||||||
|
if (!p.custom_details) {
|
||||||
|
qWarning() << "ignoring builtin provider in custom store:" << p.id;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
auto &cust = *p.custom_details;
|
||||||
|
std::shared_ptr<ModelProviderCustom> provider;
|
||||||
|
switch (p.type) {
|
||||||
|
using enum ProviderType;
|
||||||
|
case ollama:
|
||||||
|
provider = std::make_shared<OllamaProviderCustom>(
|
||||||
|
&m_customStore, p.id, cust.name, cust.base_url
|
||||||
|
);
|
||||||
|
case openai:
|
||||||
|
provider = std::make_shared<OpenaiProviderCustom>(
|
||||||
|
&m_customStore, p.id, cust.name, cust.base_url, p.openai_details.value().api_key
|
||||||
|
);
|
||||||
|
}
|
||||||
|
auto [_, unique] = m_providers.emplace(p.id, std::move(provider));
|
||||||
|
if (!unique)
|
||||||
|
qWarning() << "ignoring duplicate custom provider with id:" << p.id;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
bool ProviderRegistry::registerCustomProvider(std::unique_ptr<ModelProviderCustom> provider)
|
bool ProviderRegistry::add(std::unique_ptr<ModelProviderCustom> provider)
|
||||||
{
|
{
|
||||||
auto [_, unique] = m_providers.emplace(provider->id(), provider->asQObject());
|
auto [it, unique] = m_providers.emplace(provider->id(), std::move(provider));
|
||||||
if (unique) {
|
if (unique) {
|
||||||
m_customProviders.push_back(std::move(provider));
|
m_customProviders.push_back(std::make_unique<QUuid>(it->first));
|
||||||
emit customProviderAdded(m_customProviders.size() - 1);
|
emit customProviderAdded(m_customProviders.size() - 1);
|
||||||
}
|
}
|
||||||
return unique;
|
return unique;
|
||||||
}
|
}
|
||||||
|
|
||||||
fs::path ProviderRegistry::getSubdir()
|
auto ProviderRegistry::customProviderAt(size_t i) const -> const ModelProviderCustom *
|
||||||
|
{
|
||||||
|
auto it = m_providers.find(*m_customProviders.at(i));
|
||||||
|
Q_ASSERT(it != m_providers.end());
|
||||||
|
return &dynamic_cast<ModelProviderCustom &>(*it->second);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto ProviderRegistry::getSubdirs() -> PathSet
|
||||||
{
|
{
|
||||||
auto *mysettings = MySettings::globalInstance();
|
auto *mysettings = MySettings::globalInstance();
|
||||||
return toFSPath(mysettings->modelPath()) / "providers";
|
auto parent = toFSPath(mysettings->modelPath()) / "providers";
|
||||||
|
return { .builtin = parent, .custom = parent / "custom" };
|
||||||
}
|
}
|
||||||
|
|
||||||
void ProviderRegistry::onModelPathChanged()
|
void ProviderRegistry::onModelPathChanged()
|
||||||
{
|
{
|
||||||
auto path = getSubdir();
|
auto paths = getSubdirs();
|
||||||
if (path != m_store.path()) {
|
if (paths.builtin != m_builtinStore.path()) {
|
||||||
emit aboutToBeCleared();
|
emit aboutToBeCleared();
|
||||||
m_customProviders.clear(); // delete custom providers to release store locks
|
// delete providers to release store locks
|
||||||
if (auto res = m_store.setPath(path); !res)
|
m_customProviders.clear();
|
||||||
|
m_providers.clear();
|
||||||
|
if (auto res = m_builtinStore.setPath(paths.builtin); !res)
|
||||||
res.error().raise(); // should not happen
|
res.error().raise(); // should not happen
|
||||||
|
if (auto res = m_customStore.setPath(paths.custom); !res)
|
||||||
|
res.error().raise(); // should not happen
|
||||||
|
load();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -14,6 +14,7 @@
|
|||||||
#include <QUuid>
|
#include <QUuid>
|
||||||
#include <QtPreprocessorSupport>
|
#include <QtPreprocessorSupport>
|
||||||
|
|
||||||
|
#include <array>
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
@ -63,9 +64,7 @@ class ModelProvider {
|
|||||||
Q_PROPERTY(QUuid id READ id CONSTANT)
|
Q_PROPERTY(QUuid id READ id CONSTANT)
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
explicit ModelProvider(QUuid id) // load
|
explicit ModelProvider(QUuid id, QString name, QUrl baseUrl) // create built-in or load
|
||||||
: m_id(std::move(id)) {}
|
|
||||||
explicit ModelProvider(QUuid id, QString name, QUrl baseUrl) // create built-in
|
|
||||||
: m_id(std::move(id)), m_name(std::move(name)), m_baseUrl(std::move(baseUrl)) {}
|
: m_id(std::move(id)), m_name(std::move(name)), m_baseUrl(std::move(baseUrl)) {}
|
||||||
explicit ModelProvider(QString name, QUrl baseUrl) // create custom
|
explicit ModelProvider(QString name, QUrl baseUrl) // create custom
|
||||||
: m_name(std::move(name)), m_baseUrl(std::move(baseUrl)) {}
|
: m_name(std::move(name)), m_baseUrl(std::move(baseUrl)) {}
|
||||||
@ -93,36 +92,39 @@ protected:
|
|||||||
QUrl m_baseUrl;
|
QUrl m_baseUrl;
|
||||||
};
|
};
|
||||||
|
|
||||||
class ModelProviderBuiltin : public virtual ModelProvider {
|
// Mixin with no public interface providing basic load/save
|
||||||
|
class ModelProviderMutable : public virtual ModelProvider {
|
||||||
Q_GADGET
|
Q_GADGET
|
||||||
Q_PROPERTY(QString name READ name CONSTANT)
|
|
||||||
Q_PROPERTY(QUrl baseUrl READ baseUrl CONSTANT)
|
|
||||||
};
|
|
||||||
|
|
||||||
class ModelProviderCustom : public virtual ModelProvider {
|
|
||||||
Q_GADGET
|
|
||||||
Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged )
|
|
||||||
Q_PROPERTY(QUrl baseUrl READ baseUrl WRITE setBaseUrl NOTIFY baseUrlChanged)
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
explicit ModelProviderCustom(std::shared_ptr<ProviderStore> store)
|
explicit ModelProviderMutable(ProviderStore *store)
|
||||||
: m_store(std::move(store)) {}
|
: m_store(store) {}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
~ModelProviderCustom() noexcept override;
|
~ModelProviderMutable() noexcept override;
|
||||||
|
|
||||||
// setters
|
|
||||||
void setName (QString value) { setMemberProp<QString>(&ModelProviderCustom::m_name, "name", std::move(value)); }
|
|
||||||
void setBaseUrl(QUrl value) { setMemberProp<QUrl >(&ModelProviderCustom::m_baseUrl, "baseUrl", std::move(value)); }
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual auto load() -> const ModelProviderData::Details &;
|
|
||||||
virtual auto asData() -> ModelProviderData = 0;
|
virtual auto asData() -> ModelProviderData = 0;
|
||||||
|
|
||||||
template <typename T, typename S, typename C>
|
template <typename T, typename S, typename C>
|
||||||
void setMemberProp(this S &self, T C::* member, std::string_view name, T value);
|
void setMemberProp(this S &self, T C::* member, std::string_view name, T value);
|
||||||
|
|
||||||
std::shared_ptr<ProviderStore> m_store;
|
ProviderStore *m_store;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ModelProviderCustom : public ModelProviderMutable {
|
||||||
|
Q_GADGET
|
||||||
|
Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged )
|
||||||
|
Q_PROPERTY(QUrl baseUrl READ baseUrl WRITE setBaseUrl NOTIFY baseUrlChanged)
|
||||||
|
|
||||||
|
protected:
|
||||||
|
explicit ModelProviderCustom(ProviderStore *store)
|
||||||
|
: ModelProviderMutable(store) {}
|
||||||
|
|
||||||
|
public:
|
||||||
|
// setters
|
||||||
|
void setName (QString value) { setMemberProp<QString>(&ModelProviderCustom::m_name, "name", std::move(value)); }
|
||||||
|
void setBaseUrl(QUrl value) { setMemberProp<QUrl >(&ModelProviderCustom::m_baseUrl, "baseUrl", std::move(value)); }
|
||||||
};
|
};
|
||||||
|
|
||||||
class ProviderRegistry : public QObject {
|
class ProviderRegistry : public QObject {
|
||||||
@ -130,18 +132,26 @@ class ProviderRegistry : public QObject {
|
|||||||
QML_ELEMENT
|
QML_ELEMENT
|
||||||
QML_SINGLETON
|
QML_SINGLETON
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct PathSet { std::filesystem::path builtin, custom; };
|
||||||
|
|
||||||
|
struct BuiltinProviderData {
|
||||||
|
QUuid id;
|
||||||
|
QString name;
|
||||||
|
QUrl base_url;
|
||||||
|
};
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
explicit ProviderRegistry(std::filesystem::path path);
|
explicit ProviderRegistry(PathSet paths);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static ProviderRegistry *create(QQmlEngine *, QJSEngine *) { return new ProviderRegistry(getSubdir()); }
|
static ProviderRegistry *create(QQmlEngine *, QJSEngine *) { return new ProviderRegistry(getSubdirs()); }
|
||||||
Q_INVOKABLE void registerBuiltinProvider(ModelProviderBuiltin *provider);
|
[[nodiscard]] bool add(std::unique_ptr<ModelProviderCustom> provider);
|
||||||
[[nodiscard]] bool registerCustomProvider (std::unique_ptr<ModelProviderCustom> provider);
|
|
||||||
|
|
||||||
size_t customProviderCount() const
|
// TODO(jared): implement a way to remove custom providers via the model
|
||||||
|
[[nodiscard]] size_t customProviderCount() const
|
||||||
{ return m_customProviders.size(); }
|
{ return m_customProviders.size(); }
|
||||||
auto customProviderAt(size_t i) const -> const ModelProviderCustom *
|
[[nodiscard]] auto customProviderAt(size_t i) const -> const ModelProviderCustom *;
|
||||||
{ return m_customProviders.at(i).get(); }
|
|
||||||
auto operator[](const QUuid &id) -> ModelProviderCustom *
|
auto operator[](const QUuid &id) -> ModelProviderCustom *
|
||||||
{ return &dynamic_cast<ModelProviderCustom &>(*m_providers.at(id)); }
|
{ return &dynamic_cast<ModelProviderCustom &>(*m_providers.at(id)); }
|
||||||
|
|
||||||
@ -150,20 +160,24 @@ Q_SIGNALS:
|
|||||||
void aboutToBeCleared();
|
void aboutToBeCleared();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static auto getSubdir() -> std::filesystem::path;
|
void load();
|
||||||
|
static PathSet getSubdirs();
|
||||||
|
|
||||||
private Q_SLOTS:
|
private Q_SLOTS:
|
||||||
void onModelPathChanged();
|
void onModelPathChanged();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ProviderStore m_store;
|
static constexpr size_t N_BUILTIN = 3;
|
||||||
std::unordered_map<QUuid, QPointer<QObject>> m_providers;
|
static const std::array<BuiltinProviderData, N_BUILTIN> s_builtinProviders;
|
||||||
std::vector<std::unique_ptr<ModelProviderCustom>> m_customProviders;
|
|
||||||
|
ProviderStore m_customStore;
|
||||||
|
ProviderStore m_builtinStore;
|
||||||
|
std::unordered_map<QUuid, std::shared_ptr<ModelProvider>> m_providers;
|
||||||
|
std::vector<std::unique_ptr<QUuid>> m_customProviders;
|
||||||
};
|
};
|
||||||
|
|
||||||
class CustomProviderList : public QAbstractListModel {
|
class CustomProviderList : public QAbstractListModel {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
QML_ELEMENT
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
explicit CustomProviderList(QPointer<ProviderRegistry> registry);
|
explicit CustomProviderList(QPointer<ProviderRegistry> registry);
|
||||||
|
@ -13,9 +13,9 @@ void GenerationParams::tryParseValue(this S &self, QMap<GenerationParam, QVarian
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename T, typename S, typename C>
|
template <typename T, typename S, typename C>
|
||||||
void ModelProviderCustom::setMemberProp(this S &self, T C::* member, std::string_view name, T value)
|
void ModelProviderMutable::setMemberProp(this S &self, T C::* member, std::string_view name, T value)
|
||||||
{
|
{
|
||||||
auto &mpc = static_cast<ModelProviderCustom &>(self);
|
auto &mpc = static_cast<ModelProviderMutable &>(self);
|
||||||
auto &cur = self.*member;
|
auto &cur = self.*member;
|
||||||
if (cur != value) {
|
if (cur != value) {
|
||||||
cur = std::move(value);
|
cur = std::move(value);
|
||||||
|
34
gpt4all-chat/src/llmodel_provider_builtins.cpp
Normal file
34
gpt4all-chat/src/llmodel_provider_builtins.cpp
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
#include "llmodel_provider.h"
|
||||||
|
|
||||||
|
using namespace Qt::StringLiterals;
|
||||||
|
|
||||||
|
|
||||||
|
namespace gpt4all::ui {
|
||||||
|
|
||||||
|
|
||||||
|
// TODO: use these in the constructor of ProviderRegistry
|
||||||
|
// TODO: we have to be careful to reserve these names for ProviderStore purposes, so the user can't write JSON files that alias them.
|
||||||
|
// this *is a problem*, because we want to be able to safely introduce these.
|
||||||
|
// so we need a different namespace, i.e. a *different directory*.
|
||||||
|
const std::array<
|
||||||
|
ProviderRegistry::BuiltinProviderData, ProviderRegistry::N_BUILTIN
|
||||||
|
> ProviderRegistry::s_builtinProviders {
|
||||||
|
BuiltinProviderData {
|
||||||
|
.id = QUuid("20f963dc-1f99-441e-ad80-f30a0a06bcac"),
|
||||||
|
.name = u"Groq"_s,
|
||||||
|
.base_url = u"https://api.groq.com/openai/v1/"_s,
|
||||||
|
},
|
||||||
|
BuiltinProviderData {
|
||||||
|
.id = QUuid("6f874c3a-f1ad-47f7-9129-755c5477146c"),
|
||||||
|
.name = u"OpenAI"_s,
|
||||||
|
.base_url = u"https://api.openai.com/v1/"_s,
|
||||||
|
},
|
||||||
|
BuiltinProviderData {
|
||||||
|
.id = QUuid("7ae617b3-c0b2-4d2c-9ff2-bc3f049494cc"),
|
||||||
|
.name = u"Mistral"_s,
|
||||||
|
.base_url = u"https://api.mistral.ai/v1/"_s,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace gpt4all::ui
|
@ -73,7 +73,7 @@ auto DataStoreBase::reload() -> DataStoreResult<>
|
|||||||
if (!jv) {
|
if (!jv) {
|
||||||
(qWarning().nospace() << "skipping " << file.fileName() << "because of read error: ").noquote()
|
(qWarning().nospace() << "skipping " << file.fileName() << "because of read error: ").noquote()
|
||||||
<< jv.error().errorString();
|
<< jv.error().errorString();
|
||||||
} else if (auto [unique, uuid] = insert(*jv); !unique)
|
} else if (auto [unique, uuid] = cacheInsert(*jv); !unique)
|
||||||
qWarning() << "skipping duplicate data store entry:" << uuid;
|
qWarning() << "skipping duplicate data store entry:" << uuid;
|
||||||
file.close();
|
file.close();
|
||||||
}
|
}
|
||||||
@ -103,7 +103,7 @@ auto DataStoreBase::openNew(const QString &name) -> DataStoreResult<std::unique_
|
|||||||
return file;
|
return file;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto DataStoreBase::openExisting(const QString &name) -> DataStoreResult<std::unique_ptr<QSaveFile>>
|
auto DataStoreBase::openExisting(const QString &name, bool allowCreate) -> DataStoreResult<std::unique_ptr<QSaveFile>>
|
||||||
{
|
{
|
||||||
auto path = getFilePath(name);
|
auto path = getFilePath(name);
|
||||||
if (!QFile::exists(path))
|
if (!QFile::exists(path))
|
||||||
@ -111,7 +111,10 @@ auto DataStoreBase::openExisting(const QString &name) -> DataStoreResult<std::un
|
|||||||
std::make_error_code(std::errc::no_such_file_or_directory), path.string()
|
std::make_error_code(std::errc::no_such_file_or_directory), path.string()
|
||||||
));
|
));
|
||||||
auto file = std::make_unique<QSaveFile>(toQString(path));
|
auto file = std::make_unique<QSaveFile>(toQString(path));
|
||||||
if (!file->open(QSaveFile::WriteOnly | QSaveFile::ExistingOnly))
|
QFile::OpenMode flags = QSaveFile::WriteOnly;
|
||||||
|
if (!allowCreate)
|
||||||
|
flags |= QSaveFile::ExistingOnly;
|
||||||
|
if (!file->open(flags))
|
||||||
return std::unexpected(&*file);
|
return std::unexpected(&*file);
|
||||||
return file;
|
return file;
|
||||||
}
|
}
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
#include <expected>
|
#include <expected>
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <optional>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <unordered_set>
|
#include <unordered_set>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
@ -65,13 +66,13 @@ public:
|
|||||||
protected:
|
protected:
|
||||||
auto reload() -> DataStoreResult<>;
|
auto reload() -> DataStoreResult<>;
|
||||||
virtual auto clear() -> DataStoreResult<> = 0;
|
virtual auto clear() -> DataStoreResult<> = 0;
|
||||||
struct InsertResult { bool unique; QUuid uuid; };
|
struct CacheInsertResult { bool unique; QUuid uuid; };
|
||||||
virtual InsertResult insert(const boost::json::value &jv) = 0;
|
virtual CacheInsertResult cacheInsert(const boost::json::value &jv) = 0;
|
||||||
|
|
||||||
// helpers
|
// helpers
|
||||||
auto getFilePath(const QString &name) -> std::filesystem::path;
|
auto getFilePath(const QString &name) -> std::filesystem::path;
|
||||||
auto openNew(const QString &name) -> DataStoreResult<std::unique_ptr<QFile>>;
|
auto openNew(const QString &name) -> DataStoreResult<std::unique_ptr<QFile>>;
|
||||||
auto openExisting(const QString &name) -> DataStoreResult<std::unique_ptr<QSaveFile>>;
|
auto openExisting(const QString &name, bool allowCreate = false) -> DataStoreResult<std::unique_ptr<QSaveFile>>;
|
||||||
static auto read(QFileDevice &file, boost::json::stream_parser &parser) -> DataStoreResult<boost::json::value>;
|
static auto read(QFileDevice &file, boost::json::stream_parser &parser) -> DataStoreResult<boost::json::value>;
|
||||||
auto write(const boost::json::value &value, QFileDevice &file) -> DataStoreResult<>;
|
auto write(const boost::json::value &value, QFileDevice &file) -> DataStoreResult<>;
|
||||||
|
|
||||||
@ -94,23 +95,26 @@ public:
|
|||||||
|
|
||||||
auto list() -> tl::generator<const T &>;
|
auto list() -> tl::generator<const T &>;
|
||||||
auto setData(T data) -> DataStoreResult<>;
|
auto setData(T data) -> DataStoreResult<>;
|
||||||
|
auto createOrSetData(T data, const QString &name) -> DataStoreResult<>;
|
||||||
auto remove(const QUuid &id) -> DataStoreResult<>;
|
auto remove(const QUuid &id) -> DataStoreResult<>;
|
||||||
|
|
||||||
auto acquire(QUuid id) -> DataStoreResult<const T *>;
|
auto acquire(QUuid id) -> DataStoreResult<std::optional<const T *>>;
|
||||||
auto release(const QUuid &id) -> DataStoreResult<>;
|
auto release(const QUuid &id) -> DataStoreResult<>;
|
||||||
|
|
||||||
[[nodiscard]]
|
[[nodiscard]] auto operator[](const QUuid &id) const -> const T &
|
||||||
auto operator[](const QUuid &id) const -> const T &
|
|
||||||
{ return m_entries.at(id); }
|
{ return m_entries.at(id); }
|
||||||
|
[[nodiscard]] auto find(const QUuid &id) const -> std::optional<const T *>
|
||||||
|
{ auto it = m_entries.find(id); return it == m_entries.end() ? std::nullopt : std::optional(&*it); }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
auto createImpl(T data, const QString &name) -> DataStoreResult<const T *>;
|
auto createImpl(T data, const QString &name) -> DataStoreResult<const T *>;
|
||||||
auto clear() -> DataStoreResult<> final;
|
auto clear() -> DataStoreResult<> final;
|
||||||
InsertResult insert(const boost::json::value &jv) override;
|
CacheInsertResult cacheInsert(const boost::json::value &jv) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::unordered_map<QUuid, T> m_entries;
|
std::unordered_map<QUuid, T> m_entries;
|
||||||
std::unordered_set<QUuid> m_acquired;
|
std::unordered_set<QUuid> m_acquired;
|
||||||
|
std::unordered_map<QUuid, QString> m_names;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -51,8 +51,12 @@ auto DataStore<T>::createImpl(T data, const QString &name) -> DataStoreResult<co
|
|||||||
template <typename T>
|
template <typename T>
|
||||||
auto DataStore<T>::setData(T data) -> DataStoreResult<>
|
auto DataStore<T>::setData(T data) -> DataStoreResult<>
|
||||||
{
|
{
|
||||||
|
auto name_it = m_names.find(data.id);
|
||||||
|
if (name_it == m_names.end())
|
||||||
|
return std::unexpected(QStringLiteral("id not found: %1").arg(data.id.toString()));
|
||||||
|
|
||||||
// acquire path
|
// acquire path
|
||||||
auto file = openExisting(data.name);
|
auto file = openExisting(name_it->second);
|
||||||
if (!file)
|
if (!file)
|
||||||
return std::unexpected(file.error());
|
return std::unexpected(file.error());
|
||||||
|
|
||||||
@ -67,6 +71,32 @@ auto DataStore<T>::setData(T data) -> DataStoreResult<>
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
auto DataStore<T>::createOrSetData(T data, const QString &name) -> DataStoreResult<>
|
||||||
|
{
|
||||||
|
auto name_it = m_names.find(data.id);
|
||||||
|
if (name_it != m_names.end() && name_it->second != name)
|
||||||
|
return std::unexpected(QStringLiteral("name conflict for id %1: old=%2, new=%3")
|
||||||
|
.arg(data.id.toString(), name_it->second, name));
|
||||||
|
|
||||||
|
// acquire path
|
||||||
|
auto file = openExisting(name, /*allowCreate*/ true);
|
||||||
|
if (!file)
|
||||||
|
return std::unexpected(file.error());
|
||||||
|
|
||||||
|
// serialize
|
||||||
|
if (auto res = write(boost::json::value_from(data), **file); !res)
|
||||||
|
return std::unexpected(res.error());
|
||||||
|
if (!(*file)->commit())
|
||||||
|
return std::unexpected(file->get());
|
||||||
|
|
||||||
|
// update
|
||||||
|
m_entries[data.id] = std::move(data);
|
||||||
|
if (name_it == m_names.end())
|
||||||
|
m_names.emplace(data.id, name);
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
auto DataStore<T>::remove(const QUuid &id) -> DataStoreResult<>
|
auto DataStore<T>::remove(const QUuid &id) -> DataStoreResult<>
|
||||||
{
|
{
|
||||||
@ -89,12 +119,12 @@ auto DataStore<T>::remove(const QUuid &id) -> DataStoreResult<>
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
auto DataStore<T>::acquire(QUuid id) -> DataStoreResult<const T *>
|
auto DataStore<T>::acquire(QUuid id) -> DataStoreResult<std::optional<const T *>>
|
||||||
{
|
{
|
||||||
auto [it, unique] = m_acquired.insert(std::move(id));
|
auto [it, unique] = m_acquired.insert(std::move(id));
|
||||||
if (!unique)
|
if (!unique)
|
||||||
return std::unexpected(QStringLiteral("id already acquired: %1").arg(id.toString()));
|
return std::unexpected(QStringLiteral("id already acquired: %1").arg(id.toString()));
|
||||||
return &(*this)[*it];
|
return find(*it);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
@ -115,7 +145,7 @@ auto DataStore<T>::clear() -> DataStoreResult<>
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
auto DataStore<T>::insert(const boost::json::value &jv) -> InsertResult
|
auto DataStore<T>::cacheInsert(const boost::json::value &jv) -> CacheInsertResult
|
||||||
{
|
{
|
||||||
auto data = boost::json::value_to<T>(jv);
|
auto data = boost::json::value_to<T>(jv);
|
||||||
auto id = data.id;
|
auto id = data.id;
|
||||||
@ -124,5 +154,4 @@ auto DataStore<T>::insert(const boost::json::value &jv) -> InsertResult
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
} // namespace gpt4all::ui
|
} // namespace gpt4all::ui
|
||||||
|
@ -1,23 +1,81 @@
|
|||||||
#include "store_provider.h"
|
#include "store_provider.h"
|
||||||
|
|
||||||
|
#include "json-helpers.h" // IWYU pragma: keep
|
||||||
|
|
||||||
|
#include <gpt4all-backend/json-helpers.h> // IWYU pragma: keep
|
||||||
|
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
|
namespace json = boost::json;
|
||||||
|
|
||||||
|
|
||||||
namespace gpt4all::ui {
|
namespace gpt4all::ui {
|
||||||
|
|
||||||
|
|
||||||
|
void tag_invoke(const boost::json::value_from_tag &, boost::json::value &jv, ModelProviderData data)
|
||||||
|
{
|
||||||
|
auto &obj = jv.emplace_object();
|
||||||
|
obj = { { "id", data.id },
|
||||||
|
{ "builtin", !data.custom_details },
|
||||||
|
{ "type", data.type() } };
|
||||||
|
if (auto custom = data.custom_details) {
|
||||||
|
obj.emplace("name", custom->name);
|
||||||
|
obj.emplace("base_url", custom->base_url);
|
||||||
|
}
|
||||||
|
switch (data.type()) {
|
||||||
|
using enum ProviderType;
|
||||||
|
case openai:
|
||||||
|
obj.emplace("api_key", std::get<size_t(openai)>(data.provider_details).api_key);
|
||||||
|
case ollama:
|
||||||
|
;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto tag_invoke(const boost::json::value_to_tag<ModelProviderData> &, const boost::json::value &jv)
|
||||||
|
-> ModelProviderData
|
||||||
|
{
|
||||||
|
auto &obj = jv.as_object();
|
||||||
|
auto type = json::value_to<ProviderType>(jv.at("type"));
|
||||||
|
std::optional<CustomProviderDetails> custom_details;
|
||||||
|
if (!jv.at("builtin").as_bool())
|
||||||
|
custom_details.emplace(CustomProviderDetails {
|
||||||
|
json::value_to<QString>(jv.at("name" )),
|
||||||
|
json::value_to<QString>(jv.at("base_url")),
|
||||||
|
});
|
||||||
|
ModelProviderData::ProviderDetails provider_details;
|
||||||
|
switch (type) {
|
||||||
|
using enum ProviderType;
|
||||||
|
case openai:
|
||||||
|
provider_details = OpenaiProviderDetails { json::value_to<QString>(jv.at("api_key")) };
|
||||||
|
case ollama:
|
||||||
|
;
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
.id = json::value_to<QUuid>(obj.at("id")),
|
||||||
|
.custom_details = std::move(custom_details),
|
||||||
|
.provider_details = std::move(provider_details)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
auto ProviderStore::create(QString name, QUrl base_url, QString api_key)
|
auto ProviderStore::create(QString name, QUrl base_url, QString api_key)
|
||||||
-> DataStoreResult<const ModelProviderData *>
|
-> DataStoreResult<const ModelProviderData *>
|
||||||
{
|
{
|
||||||
ModelProviderData data { QUuid::createUuid(), ProviderType::openai, name, std::move(base_url),
|
ModelProviderData data {
|
||||||
OpenaiProviderDetails { std::move(api_key) } };
|
.id = QUuid::createUuid(),
|
||||||
|
.custom_details = CustomProviderDetails { name, std::move(base_url) },
|
||||||
|
.provider_details = OpenaiProviderDetails { std::move(api_key) },
|
||||||
|
};
|
||||||
return createImpl(std::move(data), name);
|
return createImpl(std::move(data), name);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto ProviderStore::create(QString name, QUrl base_url)
|
auto ProviderStore::create(QString name, QUrl base_url)
|
||||||
-> DataStoreResult<const ModelProviderData *>
|
-> DataStoreResult<const ModelProviderData *>
|
||||||
{
|
{
|
||||||
ModelProviderData data { QUuid::createUuid(), ProviderType::ollama, name, std::move(base_url), {} };
|
ModelProviderData data {
|
||||||
|
.id = QUuid::createUuid(),
|
||||||
|
.custom_details = CustomProviderDetails { name, std::move(base_url) },
|
||||||
|
.provider_details = {},
|
||||||
|
};
|
||||||
return createImpl(std::move(data), name);
|
return createImpl(std::move(data), name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,33 +4,43 @@
|
|||||||
|
|
||||||
#include <boost/describe/class.hpp>
|
#include <boost/describe/class.hpp>
|
||||||
#include <boost/describe/enum.hpp>
|
#include <boost/describe/enum.hpp>
|
||||||
|
#include <boost/json.hpp> // IWYU pragma: keep
|
||||||
|
|
||||||
#include <QString>
|
#include <QString>
|
||||||
#include <QUrl>
|
#include <QUrl>
|
||||||
#include <QUuid>
|
#include <QUuid>
|
||||||
|
|
||||||
#include <variant>
|
|
||||||
|
|
||||||
|
|
||||||
namespace gpt4all::ui {
|
namespace gpt4all::ui {
|
||||||
|
|
||||||
|
|
||||||
BOOST_DEFINE_ENUM_CLASS(ProviderType, openai, ollama)
|
// indices of this enum should be consistent with indices of ProviderDetails
|
||||||
|
enum class ProviderType {
|
||||||
|
openai = 0,
|
||||||
|
ollama = 1,
|
||||||
|
};
|
||||||
|
BOOST_DESCRIBE_ENUM(ProviderType, openai, ollama)
|
||||||
|
|
||||||
|
struct CustomProviderDetails {
|
||||||
|
QString name;
|
||||||
|
QUrl base_url;
|
||||||
|
};
|
||||||
|
|
||||||
struct OpenaiProviderDetails {
|
struct OpenaiProviderDetails {
|
||||||
QString api_key;
|
QString api_key;
|
||||||
};
|
};
|
||||||
BOOST_DESCRIBE_STRUCT(OpenaiProviderDetails, (), (api_key))
|
|
||||||
|
|
||||||
struct ModelProviderData {
|
struct ModelProviderData {
|
||||||
using Details = std::variant<std::monostate, OpenaiProviderDetails>;
|
using ProviderDetails = std::variant<OpenaiProviderDetails, std::monostate>;
|
||||||
QUuid id;
|
QUuid id;
|
||||||
ProviderType type;
|
std::optional<CustomProviderDetails> custom_details;
|
||||||
QString name;
|
ProviderDetails provider_details;
|
||||||
QUrl base_url;
|
|
||||||
Details details;
|
ProviderType type() const { return ProviderType(provider_details.index()); }
|
||||||
};
|
};
|
||||||
BOOST_DESCRIBE_STRUCT(ModelProviderData, (), (id, type, name, base_url, details))
|
void tag_invoke(const boost::json::value_from_tag &, boost::json::value &jv, ModelProviderData data);
|
||||||
|
auto tag_invoke(const boost::json::value_to_tag<ModelProviderData> &, const boost::json::value &jv)
|
||||||
|
-> ModelProviderData;
|
||||||
|
|
||||||
class ProviderStore : public DataStore<ModelProviderData> {
|
class ProviderStore : public DataStore<ModelProviderData> {
|
||||||
private:
|
private:
|
||||||
|
Loading…
Reference in New Issue
Block a user