C++ / fmt (pull_request) Failing after 4s
C++ / build (pull_request) Failing after 9s
JS/TS / lint (pull_request) Successful in 9s
JS/TS / fmt (pull_request) Successful in 16s
C++ / clang-tidy (pull_request) Failing after 43s
Python / static (pull_request) Failing after 57s
Rust / fmt (pull_request) Successful in 1m30s
Rust / build (pull_request) Successful in 2m5s
Rust / clippy (pull_request) Successful in 1m55s
Python / verify (pull_request) Successful in 2m23s
168 lines
3.9 KiB
C++
168 lines
3.9 KiB
C++
#include "chat.hpp"
|
|
|
|
#include "config.hpp"
|
|
#include "llm.hpp"
|
|
#include "llmclient.hpp"
|
|
#include "webfetchtool.hpp"
|
|
|
|
#include <QDebug>
|
|
|
|
namespace ZShell::llm {
|
|
|
|
Chat::Chat(QObject* parent)
|
|
: QObject(parent)
|
|
, m_store(new ChatStore(this))
|
|
, m_client(new LlmClient(this)) {
|
|
if (!config::Config::instance()) new config::Config();
|
|
|
|
m_store->setLlmClient(m_client);
|
|
m_client->tools()->registerTool(new WebFetchTool(m_client->tools()));
|
|
|
|
const auto* llm = config::Config::instance()->llm();
|
|
m_client->setEndpoint(llm->endpoint());
|
|
m_client->setModel(llm->model());
|
|
m_client->setTemperature(llm->temperature());
|
|
m_client->setToolsEnabled(llm->tools());
|
|
|
|
connect(llm, &config::Llm::endpointChanged, this, [this, llm]() {
|
|
m_client->setEndpoint(llm->endpoint());
|
|
});
|
|
connect(llm, &config::Llm::modelChanged, this, [this, llm]() {
|
|
m_client->setModel(llm->model());
|
|
});
|
|
connect(llm, &config::Llm::temperatureChanged, this, [this, llm]() {
|
|
m_client->setTemperature(llm->temperature());
|
|
});
|
|
connect(llm, &config::Llm::toolsChanged, this, [this, llm]() {
|
|
m_client->setToolsEnabled(llm->tools());
|
|
});
|
|
|
|
connect(m_client, &LlmClient::busyChanged, this, [this]() {
|
|
// A fresh run supersedes the previous error.
|
|
if (m_client->busy() && !m_lastError.isEmpty()) {
|
|
m_lastError.clear();
|
|
Q_EMIT lastErrorChanged();
|
|
}
|
|
Q_EMIT busyChanged();
|
|
});
|
|
connect(m_client, &LlmClient::endpointChanged, this, &Chat::endpointChanged);
|
|
connect(m_client, &LlmClient::modelChanged, this, &Chat::modelChanged);
|
|
connect(
|
|
m_client,
|
|
&LlmClient::availableModelsChanged,
|
|
this,
|
|
&Chat::availableModelsChanged);
|
|
connect(
|
|
m_client,
|
|
&LlmClient::contextSizeChanged,
|
|
this,
|
|
&Chat::contextSizeChanged);
|
|
connect(
|
|
m_client,
|
|
&LlmClient::streamingChatIdChanged,
|
|
this,
|
|
&Chat::streamingChatIdChanged);
|
|
connect(
|
|
m_client,
|
|
&LlmClient::toolsEnabledChanged,
|
|
this,
|
|
&Chat::toolsEnabledChanged);
|
|
connect(
|
|
m_client,
|
|
&LlmClient::errorOccurred,
|
|
this,
|
|
[this](const QString& message) {
|
|
m_lastError = message;
|
|
Q_EMIT lastErrorChanged();
|
|
Q_EMIT errorOccurred(message);
|
|
});
|
|
connect(
|
|
m_store,
|
|
&ChatStore::sessionRemoved,
|
|
this,
|
|
[this](ChatSession* session) { m_client->sessionRemoved(session); });
|
|
connect(
|
|
m_client,
|
|
&LlmClient::titleSuggested,
|
|
this,
|
|
[this](ChatSession* session, const QString& title) {
|
|
qInfo() << "Chat: applying generated title" << session->id()
|
|
<< title << "(was" << session->title() << ")";
|
|
session->setTitle(title);
|
|
m_store->saveMeta(session);
|
|
});
|
|
connect(
|
|
m_client,
|
|
&LlmClient::iconSuggested,
|
|
this,
|
|
[this](ChatSession* session, const QString& icon) {
|
|
qInfo() << "Chat: applying generated icon" << session->id() << icon
|
|
<< "(was" << session->icon() << ")";
|
|
session->setIcon(icon);
|
|
m_store->saveMeta(session);
|
|
});
|
|
}
|
|
|
|
bool Chat::busy() const {
|
|
return m_client->busy();
|
|
}
|
|
|
|
QString Chat::endpoint() const {
|
|
return m_client->endpoint();
|
|
}
|
|
|
|
QString Chat::model() const {
|
|
return m_client->model();
|
|
}
|
|
|
|
QStringList Chat::availableModels() const {
|
|
return m_client->availableModels();
|
|
}
|
|
|
|
int Chat::contextSize() const {
|
|
return m_client->contextSize();
|
|
}
|
|
|
|
bool Chat::toolsEnabled() const {
|
|
return m_client->toolsEnabled();
|
|
}
|
|
|
|
void Chat::setToolsEnabled(bool value) {
|
|
m_client->setToolsEnabled(value);
|
|
if (auto* config = config::Config::instance())
|
|
config->llm()->set_tools(value);
|
|
}
|
|
|
|
QString Chat::streamingChatId() const {
|
|
return m_client->streamingChatId();
|
|
}
|
|
|
|
Chat* Chat::s_instance = nullptr;
|
|
|
|
Chat* Chat::create(QQmlEngine*, QJSEngine*) {
|
|
if (!s_instance) s_instance = new Chat();
|
|
return s_instance;
|
|
}
|
|
|
|
void Chat::stop() {
|
|
m_client->stop();
|
|
}
|
|
|
|
void Chat::dismissError() {
|
|
if (m_lastError.isEmpty()) return;
|
|
m_lastError.clear();
|
|
Q_EMIT lastErrorChanged();
|
|
}
|
|
|
|
void Chat::refreshModels() {
|
|
m_client->refreshModels();
|
|
}
|
|
|
|
void Chat::selectModel(const QString& id) {
|
|
if (id.isEmpty()) return;
|
|
m_client->setModel(id);
|
|
if (auto* config = config::Config::instance()) config->llm()->set_model(id);
|
|
}
|
|
|
|
} // namespace ZShell::llm
|