Add basic chat widgets and functionality

This commit is contained in:
Petr Mironychev
2024-09-15 01:58:56 +02:00
parent 6e56646b4c
commit 04c44f5916
37 changed files with 1422 additions and 369 deletions

View File

@ -35,6 +35,7 @@ public:
virtual QString name() const = 0;
virtual QString url() const = 0;
virtual QString completionEndpoint() const = 0;
virtual QString chatEndpoint() const = 0;
virtual void prepareRequest(QJsonObject &request) = 0;
virtual bool handleResponse(QNetworkReply *reply, QString &accumulatedResponse) = 0;

View File

@ -48,12 +48,14 @@ QString LMStudioProvider::completionEndpoint() const
return "/v1/chat/completions";
}
QString LMStudioProvider::chatEndpoint() const
{
return "/v1/chat/completions";
}
void LMStudioProvider::prepareRequest(QJsonObject &request)
{
auto &settings = Settings::presetPromptsSettings();
const auto &currentTemplate = PromptTemplateManager::instance().getCurrentTemplate();
if (currentTemplate->name() == "Custom Template")
return;
if (request.contains("prompt")) {
QJsonArray messages{
{QJsonObject{{"role", "user"}, {"content", request.take("prompt").toString()}}}};
@ -62,7 +64,6 @@ void LMStudioProvider::prepareRequest(QJsonObject &request)
request["max_tokens"] = settings.maxTokens();
request["temperature"] = settings.temperature();
request["stop"] = QJsonArray::fromStringList(currentTemplate->stopWords());
if (settings.useTopP())
request["top_p"] = settings.topP();
if (settings.useTopK())

View File

@ -31,6 +31,7 @@ public:
QString name() const override;
QString url() const override;
QString completionEndpoint() const override;
QString chatEndpoint() const override;
void prepareRequest(QJsonObject &request) override;
bool handleResponse(QNetworkReply *reply, QString &accumulatedResponse) override;
QList<QString> getInstalledModels(const Utils::Environment &env) override;

View File

@ -48,18 +48,19 @@ QString OllamaProvider::completionEndpoint() const
return "/api/generate";
}
QString OllamaProvider::chatEndpoint() const
{
return "/api/chat";
}
void OllamaProvider::prepareRequest(QJsonObject &request)
{
auto &settings = Settings::presetPromptsSettings();
auto currentTemplate = PromptTemplateManager::instance().getCurrentTemplate();
if (currentTemplate->name() == "Custom Template")
return;
QJsonObject options;
options["num_predict"] = settings.maxTokens();
options["keep_alive"] = settings.ollamaLivetime();
options["temperature"] = settings.temperature();
options["stop"] = QJsonArray::fromStringList(currentTemplate->stopWords());
if (settings.useTopP())
options["top_p"] = settings.topP();
if (settings.useTopK())
@ -73,28 +74,52 @@ void OllamaProvider::prepareRequest(QJsonObject &request)
bool OllamaProvider::handleResponse(QNetworkReply *reply, QString &accumulatedResponse)
{
QString endpoint = reply->url().path();
bool isComplete = false;
while (reply->canReadLine()) {
QByteArray line = reply->readLine().trimmed();
if (line.isEmpty()) {
continue;
}
QJsonDocument jsonResponse = QJsonDocument::fromJson(line);
if (jsonResponse.isNull()) {
qWarning() << "Invalid JSON response from Ollama:" << line;
QJsonDocument doc = QJsonDocument::fromJson(line);
if (doc.isNull()) {
logMessage("Invalid JSON response from Ollama: " + QString::fromUtf8(line));
continue;
}
QJsonObject responseObj = jsonResponse.object();
if (responseObj.contains("response")) {
QString completion = responseObj["response"].toString();
accumulatedResponse += completion;
QJsonObject responseObj = doc.object();
if (responseObj.contains("error")) {
QString errorMessage = responseObj["error"].toString();
logMessage("Error in Ollama response: " + errorMessage);
return false;
}
if (responseObj["done"].toBool()) {
if (endpoint == completionEndpoint()) {
if (responseObj.contains("response")) {
QString completion = responseObj["response"].toString();
accumulatedResponse += completion;
}
} else if (endpoint == chatEndpoint()) {
if (responseObj.contains("message")) {
QJsonObject message = responseObj["message"].toObject();
if (message.contains("content")) {
QString content = message["content"].toString();
accumulatedResponse += content;
}
}
} else {
logMessage("Unknown endpoint: " + endpoint);
}
if (responseObj.contains("done") && responseObj["done"].toBool()) {
isComplete = true;
break;
}
}
return isComplete;
}

View File

@ -31,6 +31,7 @@ public:
QString name() const override;
QString url() const override;
QString completionEndpoint() const override;
QString chatEndpoint() const override;
void prepareRequest(QJsonObject &request) override;
bool handleResponse(QNetworkReply *reply, QString &accumulatedResponse) override;
QList<QString> getInstalledModels(const Utils::Environment &env) override;

View File

@ -46,13 +46,14 @@ QString OpenAICompatProvider::completionEndpoint() const
return "/v1/chat/completions";
}
QString OpenAICompatProvider::chatEndpoint() const
{
return "/v1/chat/completions";
}
void OpenAICompatProvider::prepareRequest(QJsonObject &request)
{
auto &settings = Settings::presetPromptsSettings();
const auto &currentTemplate = PromptTemplateManager::instance().getCurrentTemplate();
if (currentTemplate->name() == "Custom Template")
return;
if (request.contains("prompt")) {
QJsonArray messages{
{QJsonObject{{"role", "user"}, {"content", request.take("prompt").toString()}}}};
@ -61,7 +62,6 @@ void OpenAICompatProvider::prepareRequest(QJsonObject &request)
request["max_tokens"] = settings.maxTokens();
request["temperature"] = settings.temperature();
request["stop"] = QJsonArray::fromStringList(currentTemplate->stopWords());
if (settings.useTopP())
request["top_p"] = settings.topP();
if (settings.useTopK())

View File

@ -31,6 +31,7 @@ public:
QString name() const override;
QString url() const override;
QString completionEndpoint() const override;
QString chatEndpoint() const override;
void prepareRequest(QJsonObject &request) override;
bool handleResponse(QNetworkReply *reply, QString &accumulatedResponse) override;
QList<QString> getInstalledModels(const Utils::Environment &env) override;