-
-
Notifications
You must be signed in to change notification settings - Fork 414
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
#3026 add: basic auto-completion api and settings dialog
- Loading branch information
Showing
7 changed files
with
270 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,125 @@ | ||
/* | ||
* Copyright (c) 2014-2024 Patrizio Bekerle -- <patrizio@bekerle.com> | ||
* | ||
* This program is free software; you can redistribute it and/or modify | ||
* it under the terms of the GNU General Public License as published by | ||
* the Free Software Foundation; version 2 of the License. | ||
* | ||
* This program is distributed in the hope that it will be useful, but | ||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY | ||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | ||
* for more details. | ||
* | ||
*/ | ||
|
||
#include "openaiservice.h" | ||
#include <QJsonObject> | ||
#include <QJsonDocument> | ||
#include <QJsonArray> | ||
#include <QNetworkRequest> | ||
#include <utility> | ||
|
||
using namespace std; | ||
|
||
QT_USE_NAMESPACE | ||
|
||
OpenAiService::OpenAiService(QObject* parent) | ||
: QObject(parent) { | ||
auto apiKey = "secret"; | ||
auto _completer = new OpenAiCompleter( | ||
apiKey, | ||
"llama3-8b-8192", | ||
"https://api.groq.com/openai/v1/chat/completions", | ||
parent); | ||
|
||
_completer->complete("Who am I?"); | ||
|
||
QObject::connect(_completer, &OpenAiCompleter::completed, this, [this](const QString& result) { | ||
qDebug() << "'result': " << result; | ||
}); | ||
|
||
QObject::connect(_completer, &OpenAiCompleter::errorOccurred, this, [this](const QString& errorString) { | ||
qDebug() << "'errorString': " << errorString; | ||
}); | ||
} | ||
|
||
OpenAiCompleter::OpenAiCompleter(QString apiKey, QString modelId, QString apiBaseUrl, QObject* parent) | ||
: QObject(parent), apiKey(std::move(apiKey)), apiBaseUrl(std::move(apiBaseUrl)), modelId(std::move(modelId)) | ||
{ | ||
networkManager = new QNetworkAccessManager(this); | ||
connect(networkManager, &QNetworkAccessManager::finished, this, &OpenAiCompleter::replyFinished); | ||
} | ||
|
||
void OpenAiCompleter::complete(const QString& prompt) | ||
{ | ||
QUrl url(apiBaseUrl); | ||
QNetworkRequest request(url); | ||
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json"); | ||
request.setRawHeader("Authorization", ("Bearer " + apiKey).toUtf8()); | ||
|
||
QJsonObject json; | ||
json["model"] = modelId; // Use the modelId set in the constructor or by setModelId | ||
|
||
QJsonArray messagesArray; | ||
QJsonObject messageObject; | ||
messageObject["role"] = "user"; | ||
messageObject["content"] = prompt; | ||
messagesArray.append(messageObject); | ||
|
||
json["messages"] = messagesArray; | ||
|
||
qDebug() << __func__ << " - 'json': " << json; | ||
|
||
QJsonDocument doc(json); | ||
QByteArray data = doc.toJson(); | ||
|
||
networkManager->post(request, data); | ||
} | ||
|
||
void OpenAiCompleter::setApiBaseUrl(const QString& url) { | ||
this->apiBaseUrl = url; | ||
} | ||
|
||
void OpenAiCompleter::setModelId(const QString& id) { | ||
this->modelId = id; | ||
} | ||
|
||
void OpenAiCompleter::replyFinished(QNetworkReply* reply) | ||
{ | ||
if (reply->error()) { | ||
emit errorOccurred(reply->errorString()); | ||
return; | ||
} | ||
|
||
QByteArray response_data = reply->readAll(); | ||
QJsonDocument json = QJsonDocument::fromJson(response_data); | ||
QJsonObject jsonObject = json.object(); | ||
QJsonArray choices = jsonObject["choices"].toArray(); | ||
|
||
// Initializing an empty result string to hold the eventual content. | ||
QString text = ""; | ||
|
||
// Look through the choices (though typically there's only one) | ||
// and parse the nested message content. | ||
if(!choices.isEmpty()) { | ||
QJsonObject firstChoice = choices[0].toObject(); | ||
|
||
// Check if 'message' field exists, ensuring compatibility with the new structure | ||
if(firstChoice.contains("message")) { | ||
QJsonObject message = firstChoice["message"].toObject(); | ||
// Check if the role is "assistant" before extracting content | ||
if(message["role"].toString() == "assistant") { | ||
text = message["content"].toString(); | ||
} | ||
} else { // Fallback to directly parse 'text' if present, for backward compatibility or other responses | ||
text = firstChoice["text"].toString(); | ||
} | ||
|
||
emit completed(text.trimmed()); | ||
} | ||
else { | ||
emit errorOccurred("No choices found in the response"); | ||
} | ||
|
||
reply->deleteLater(); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
/* | ||
* Copyright (c) 2014-2024 Patrizio Bekerle -- <patrizio@bekerle.com> | ||
* | ||
* This program is free software; you can redistribute it and/or modify | ||
* it under the terms of the GNU General Public License as published by | ||
* the Free Software Foundation; version 2 of the License. | ||
* | ||
* This program is distributed in the hope that it will be useful, but | ||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY | ||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | ||
* for more details. | ||
* | ||
*/ | ||
|
||
#pragma once | ||
|
||
#include <QObject> | ||
#include <QNetworkAccessManager> | ||
#include <QNetworkReply> | ||
|
||
class OpenAiService : public QObject | ||
{ | ||
Q_OBJECT | ||
public: | ||
explicit OpenAiService(QObject* parent = nullptr); | ||
}; | ||
|
||
|
||
class OpenAiCompleter : public QObject | ||
{ | ||
Q_OBJECT | ||
public: | ||
explicit OpenAiCompleter(QString apiKey, QString modelId, QString apiBaseUrl = "https://api.openai.com/v1/completions", QObject* parent = nullptr); | ||
void complete(const QString& prompt); | ||
void setApiBaseUrl(const QString& url); | ||
void setModelId(const QString& id); | ||
|
||
signals: | ||
void completed(QString result); | ||
void errorOccurred(QString errorString); | ||
|
||
private slots: | ||
void replyFinished(QNetworkReply* reply); | ||
|
||
private: | ||
QNetworkAccessManager* networkManager; | ||
QString apiKey; | ||
QString apiBaseUrl; // Store the API base URL | ||
QString modelId; // Model ID used for API requests | ||
}; |