general ui work
This commit is contained in:
49
backend.cpp
49
backend.cpp
@ -1,8 +1,11 @@
|
|||||||
#include "backend.h"
|
#include "backend.h"
|
||||||
|
#include "exllama.h"
|
||||||
|
#include <qstringliteral.h>
|
||||||
|
|
||||||
AiBackend::Request::Request(const QString& textIn, void* userPtrIn):
|
AiBackend::Request::Request(const QString& textIn, type_t typeIn, void* userPtrIn):
|
||||||
text(textIn),
|
text(textIn),
|
||||||
userPtr(userPtrIn)
|
userPtr(userPtrIn),
|
||||||
|
type(typeIn)
|
||||||
{
|
{
|
||||||
id = idCounter++;
|
id = idCounter++;
|
||||||
}
|
}
|
||||||
@ -27,13 +30,21 @@ bool AiBackend::Request::operator==(const Request& in)
|
|||||||
return id == in.id;
|
return id == in.id;
|
||||||
}
|
}
|
||||||
|
|
||||||
AiBackend::Response::Response(QString textIn, uint32_t idIn, bool finishedIn, void* userPtrIn):
|
AiBackend::Request::type_t AiBackend::Request::getType() const
|
||||||
AiBackend::Request::Request(textIn, userPtrIn),
|
{
|
||||||
finished(finishedIn)
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
AiBackend::Response::Response(QString textIn, uint32_t idIn, bool finishedIn,
|
||||||
|
AiBackend::Request::type_t type, int64_t tokensIn, void* userPtrIn):
|
||||||
|
AiBackend::Request::Request(textIn, type, userPtrIn),
|
||||||
|
finished(finishedIn),
|
||||||
|
tokens(tokensIn)
|
||||||
{
|
{
|
||||||
id = idIn;
|
id = idIn;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool AiBackend::Response::isFinished() const
|
bool AiBackend::Response::isFinished() const
|
||||||
{
|
{
|
||||||
return finished;
|
return finished;
|
||||||
@ -44,10 +55,32 @@ void AiBackend::Response::setUserPtr(void* ptr)
|
|||||||
userPtr = ptr;
|
userPtr = ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AiBackend::generate(const Request& request)
|
std::vector<QString> AiBackend::getAvailableBackendNames()
|
||||||
{
|
{
|
||||||
m_requests.insert(request.getId(), request);
|
return {QStringLiteral("KoboldAI"), ExLlama::backendNameStatic()};
|
||||||
generateImpl(request);
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<AiBackend> AiBackend::createBackend(const QString& name)
|
||||||
|
{
|
||||||
|
if(name == QStringLiteral("KoboldAI"))
|
||||||
|
return nullptr;
|
||||||
|
if(name == ExLlama::backendNameStatic())
|
||||||
|
return std::shared_ptr<ExLlama>(new ExLlama());
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AiBackend::generate(const Request& request)
|
||||||
|
{
|
||||||
|
if(request.getType() == Request::UNKOWN)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
bool ret = generateImpl(request);
|
||||||
|
|
||||||
|
if(ret)
|
||||||
|
m_requests.insert(request.getId(), request);
|
||||||
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AiBackend::isValidId(uint32_t id)
|
bool AiBackend::isValidId(uint32_t id)
|
||||||
|
27
backend.h
27
backend.h
@ -7,6 +7,7 @@
|
|||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <QUrl>
|
#include <QUrl>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
class AiBackend: public QObject
|
class AiBackend: public QObject
|
||||||
{
|
{
|
||||||
@ -21,17 +22,28 @@ public:
|
|||||||
|
|
||||||
class Request
|
class Request
|
||||||
{
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
INFERENCE,
|
||||||
|
COUNT_TOKENS,
|
||||||
|
LEFT_TRIM,
|
||||||
|
UNKOWN
|
||||||
|
} type_t;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
inline static uint32_t idCounter = 0;
|
inline static uint32_t idCounter = 0;
|
||||||
QString text;
|
QString text;
|
||||||
uint32_t id;
|
uint32_t id;
|
||||||
void* userPtr;
|
void* userPtr;
|
||||||
|
type_t type;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Request() = default;
|
Request() = default;
|
||||||
Request(const QString& text, void* userPtr = nullptr);
|
Request(const QString& text, type_t type = UNKOWN, void* userPtr = nullptr);
|
||||||
const QString& getText() const;
|
const QString& getText() const;
|
||||||
uint32_t getId() const;
|
uint32_t getId() const;
|
||||||
|
type_t getType() const;
|
||||||
bool operator==(const Request& in);
|
bool operator==(const Request& in);
|
||||||
void* getUserPtr() const;
|
void* getUserPtr() const;
|
||||||
};
|
};
|
||||||
@ -40,11 +52,14 @@ public:
|
|||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
bool finished;
|
bool finished;
|
||||||
|
int64_t tokens = -1;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Response() = default;
|
Response() = default;
|
||||||
Response(QString text, uint32_t id, bool finished, void* userPtr = nullptr);
|
Response(QString text, uint32_t id, bool finished, type_t type = UNKOWN, int64_t tokens= -1, void* userPtr = nullptr);
|
||||||
bool isFinished() const;
|
bool isFinished() const;
|
||||||
|
int64_t getTokens() const;
|
||||||
|
|
||||||
void setUserPtr(void* ptr);
|
void setUserPtr(void* ptr);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -53,12 +68,15 @@ protected:
|
|||||||
|
|
||||||
void feedResponse(Response response);
|
void feedResponse(Response response);
|
||||||
bool isValidId(uint32_t id);
|
bool isValidId(uint32_t id);
|
||||||
virtual void generateImpl(const Request& request) = 0;
|
virtual bool generateImpl(const Request& request) = 0;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
static std::vector<QString> getAvailableBackendNames();
|
||||||
|
static std::shared_ptr<AiBackend> createBackend(const QString& name);
|
||||||
|
virtual QString backendName() = 0;
|
||||||
virtual bool ready() = 0;
|
virtual bool ready() = 0;
|
||||||
void generate(const Request& request);
|
bool generate(const Request& request);
|
||||||
virtual void abort(uint64_t id){(void)id;}
|
virtual void abort(uint64_t id){(void)id;}
|
||||||
virtual void open(const QUrl& url){(void)url;};
|
virtual void open(const QUrl& url){(void)url;};
|
||||||
Q_SIGNAL void gotResponse(Response response);
|
Q_SIGNAL void gotResponse(Response response);
|
||||||
@ -68,3 +86,4 @@ public:
|
|||||||
|
|
||||||
Q_DECLARE_METATYPE(AiBackend::Response);
|
Q_DECLARE_METATYPE(AiBackend::Response);
|
||||||
Q_DECLARE_METATYPE(AiBackend::Request);
|
Q_DECLARE_METATYPE(AiBackend::Request);
|
||||||
|
|
||||||
|
90
exllama.cpp
90
exllama.cpp
@ -1,7 +1,9 @@
|
|||||||
#include "exllama.h"
|
#include "exllama.h"
|
||||||
|
#include "backend.h"
|
||||||
|
|
||||||
#include <QJsonObject>
|
#include <QJsonObject>
|
||||||
#include <QJsonDocument>
|
#include <QJsonDocument>
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
ExLlama::ExLlama()
|
ExLlama::ExLlama()
|
||||||
{
|
{
|
||||||
@ -17,11 +19,6 @@ void ExLlama::socketMessage(const QString& message)
|
|||||||
{
|
{
|
||||||
QJsonDocument jsonDocument = QJsonDocument::fromJson(message.toUtf8());
|
QJsonDocument jsonDocument = QJsonDocument::fromJson(message.toUtf8());
|
||||||
QJsonValue idVal = jsonDocument[QStringLiteral("request_id")];
|
QJsonValue idVal = jsonDocument[QStringLiteral("request_id")];
|
||||||
if(!idVal.isDouble())
|
|
||||||
{
|
|
||||||
qDebug()<<"Got invalid response on socket";
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
int id = idVal.toInt();
|
int id = idVal.toInt();
|
||||||
|
|
||||||
if(!isValidId(id))
|
if(!isValidId(id))
|
||||||
@ -30,29 +27,90 @@ void ExLlama::socketMessage(const QString& message)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
QJsonValue responseValue = jsonDocument[QStringLiteral("response")];
|
Response::type_t type = strToAction(jsonDocument[QStringLiteral("action")].toString());
|
||||||
|
QJsonValue responseValue;
|
||||||
|
int64_t tokens = -1;
|
||||||
|
|
||||||
|
if(type == Response::INFERENCE)
|
||||||
|
{
|
||||||
|
responseValue = jsonDocument[QStringLiteral("response")];
|
||||||
|
}
|
||||||
|
else if(type == Response::COUNT_TOKENS)
|
||||||
|
{
|
||||||
|
responseValue = QJsonValue(QStringLiteral(""));
|
||||||
|
QJsonValue tokensValue = jsonDocument[QStringLiteral("num_tokens")];
|
||||||
|
if(!tokensValue.isDouble())
|
||||||
|
{
|
||||||
|
qDebug()<<"Got invalid response on socket, num_tokens missing or not a number";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
tokens = tokensValue.toInt();
|
||||||
|
}
|
||||||
|
else if(type == Response::LEFT_TRIM)
|
||||||
|
{
|
||||||
|
responseValue = jsonDocument[QStringLiteral("trimmed_text")];
|
||||||
|
}
|
||||||
|
|
||||||
if(!responseValue.isString())
|
if(!responseValue.isString())
|
||||||
{
|
{
|
||||||
qDebug()<<"Got invalid response on socket";
|
qDebug()<<"Got invalid response on socket";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
feedResponse(Response(responseValue.toString(), id, true));
|
feedResponse(Response(responseValue.toString(), id, true, type, tokens));
|
||||||
}
|
}
|
||||||
|
|
||||||
void ExLlama::generateImpl(const Request& request)
|
const QString ExLlama::actionToStr(AiBackend::Request::type_t type)
|
||||||
{
|
{
|
||||||
|
switch(type)
|
||||||
|
{
|
||||||
|
case Request::INFERENCE:
|
||||||
|
return QStringLiteral("infer");
|
||||||
|
case Request::COUNT_TOKENS:
|
||||||
|
return QStringLiteral("estimate_token");
|
||||||
|
case Request::LEFT_TRIM:
|
||||||
|
return QStringLiteral("lefttrim_token");
|
||||||
|
default:
|
||||||
|
return QString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
AiBackend::Request::type_t ExLlama::strToAction(const QString& str)
|
||||||
|
{
|
||||||
|
if(str == QStringLiteral("infer"))
|
||||||
|
return Request::INFERENCE;
|
||||||
|
else if(str == QStringLiteral("estimate_token"))
|
||||||
|
return Request::COUNT_TOKENS;
|
||||||
|
else if(str == QStringLiteral("lefttrim_token"))
|
||||||
|
return Request::LEFT_TRIM;
|
||||||
|
else
|
||||||
|
return Request::UNKOWN;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ExLlama::generateImpl(const Request& request)
|
||||||
|
{
|
||||||
|
QString action = actionToStr(request.getType());
|
||||||
|
|
||||||
|
if(action.isEmpty())
|
||||||
|
return false;
|
||||||
|
|
||||||
QJsonObject json;
|
QJsonObject json;
|
||||||
json[QStringLiteral("action")] = QStringLiteral("infer");
|
json[QStringLiteral("action")] = action;
|
||||||
json[QStringLiteral("request_id")] = static_cast<double>(request.getId());
|
json[QStringLiteral("request_id")] = static_cast<double>(request.getId());
|
||||||
json[QStringLiteral("text")] = request.getText();
|
json[QStringLiteral("text")] = request.getText();
|
||||||
json[QStringLiteral("max_new_tokens")] = 50;
|
|
||||||
json[QStringLiteral("stream")] = false;
|
if(request.getType() == Request::INFERENCE)
|
||||||
|
{
|
||||||
|
json[QStringLiteral("max_new_tokens")] = 50;
|
||||||
|
json[QStringLiteral("stream")] = false;
|
||||||
|
}
|
||||||
|
|
||||||
QJsonDocument jsonDocument(json);
|
QJsonDocument jsonDocument(json);
|
||||||
QString requestText = QString::fromUtf8(jsonDocument.toJson(QJsonDocument::JsonFormat::Compact));
|
QString requestText = QString::fromUtf8(jsonDocument.toJson(QJsonDocument::JsonFormat::Compact));
|
||||||
qDebug()<<__func__<<' '<<requestText;
|
qDebug()<<__func__<<' '<<requestText;
|
||||||
m_webSocket.sendTextMessage(requestText);
|
m_webSocket.sendTextMessage(requestText);
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ExLlama::open(const QUrl& url)
|
void ExLlama::open(const QUrl& url)
|
||||||
@ -61,6 +119,16 @@ void ExLlama::open(const QUrl& url)
|
|||||||
m_webSocket.open(url);
|
m_webSocket.open(url);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString ExLlama::backendName()
|
||||||
|
{
|
||||||
|
return backendNameStatic();
|
||||||
|
}
|
||||||
|
|
||||||
|
QString ExLlama::backendNameStatic()
|
||||||
|
{
|
||||||
|
return QStringLiteral("ExLlama");
|
||||||
|
}
|
||||||
|
|
||||||
ExLlama::~ExLlama()
|
ExLlama::~ExLlama()
|
||||||
{
|
{
|
||||||
m_webSocket.disconnect();
|
m_webSocket.disconnect();
|
||||||
|
@ -13,13 +13,19 @@ private:
|
|||||||
|
|
||||||
void socketMessage(const QString& message);
|
void socketMessage(const QString& message);
|
||||||
|
|
||||||
|
static const QString actionToStr(Request::type_t type);
|
||||||
|
static Request::type_t strToAction(const QString& str);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual void generateImpl(const Request& request) override;
|
virtual bool generateImpl(const Request& request) override;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ExLlama();
|
ExLlama();
|
||||||
virtual bool ready() override;
|
virtual bool ready() override;
|
||||||
virtual void open(const QUrl& url) override;
|
virtual void open(const QUrl& url) override;
|
||||||
|
virtual QString backendName() override;
|
||||||
|
static QString backendNameStatic();
|
||||||
|
|
||||||
virtual ~ExLlama();
|
virtual ~ExLlama();
|
||||||
|
|
||||||
};
|
};
|
||||||
|
72
kateai.cpp
72
kateai.cpp
@ -8,6 +8,7 @@
|
|||||||
#include <qdebug.h>
|
#include <qdebug.h>
|
||||||
#include <qhash.h>
|
#include <qhash.h>
|
||||||
#include <qjsonobject.h>
|
#include <qjsonobject.h>
|
||||||
|
#include <qmessagebox.h>
|
||||||
#include <qnamespace.h>
|
#include <qnamespace.h>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
#include <KActionCollection>
|
#include <KActionCollection>
|
||||||
@ -18,6 +19,7 @@
|
|||||||
#include <QTextCodec>
|
#include <QTextCodec>
|
||||||
#include <limits>
|
#include <limits>
|
||||||
#include <QMessageBox>
|
#include <QMessageBox>
|
||||||
|
#include <QInputDialog>
|
||||||
#include <KLocalizedString>
|
#include <KLocalizedString>
|
||||||
#include <KSharedConfig>
|
#include <KSharedConfig>
|
||||||
|
|
||||||
@ -62,12 +64,15 @@ void KateAiPlugin::readConfig()
|
|||||||
KConfigGroup config(KSharedConfig::openConfig(), "Ai");
|
KConfigGroup config(KSharedConfig::openConfig(), "Ai");
|
||||||
m_serverUrl = QUrl(config.readEntry("Url", "ws://localhost:8642"));
|
m_serverUrl = QUrl(config.readEntry("Url", "ws://localhost:8642"));
|
||||||
reconnect();
|
reconnect();
|
||||||
|
|
||||||
|
KateAiPluginView::setInstruct(config.readEntry("Instruct", false));
|
||||||
|
KateAiPluginView::setSystemPrompt(config.readEntry("SystemPrompt", "You are an intelligent programming assistant."));
|
||||||
|
KateAiPluginView::setMaxContext(config.readEntry("Context", 1024));
|
||||||
}
|
}
|
||||||
|
|
||||||
KateAiPluginView::KateAiPluginView(KateAiPlugin *plugin, KTextEditor::MainWindow *mainwindow, bool instruct)
|
KateAiPluginView::KateAiPluginView(KateAiPlugin *plugin, KTextEditor::MainWindow *mainwindow)
|
||||||
: QObject(plugin)
|
: QObject(plugin)
|
||||||
, m_mainWindow(mainwindow)
|
, m_mainWindow(mainwindow)
|
||||||
, m_useInstruct(instruct)
|
|
||||||
{
|
{
|
||||||
KXMLGUIClient::setComponentName(QStringLiteral("kateaiplugin"), QStringLiteral("Kate Ai"));
|
KXMLGUIClient::setComponentName(QStringLiteral("kateaiplugin"), QStringLiteral("Kate Ai"));
|
||||||
setXMLFile(QStringLiteral("ui.rc"));
|
setXMLFile(QStringLiteral("ui.rc"));
|
||||||
@ -143,21 +148,28 @@ QStringList KateAiPluginView::getIncludePaths(const QString& text)
|
|||||||
return paths;
|
return paths;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString KateAiPluginView::assembleContext(QPointer<KTextEditor::Document> document, const KTextEditor::Cursor& cursor)
|
QString KateAiPluginView::assembleContext(QPointer<KTextEditor::Document> document,
|
||||||
|
const KTextEditor::Cursor& cursor, const QString& instruction)
|
||||||
{
|
{
|
||||||
QString mime = document->mimeType();
|
QString mime = document->mimeType();
|
||||||
QString context;
|
QString context;
|
||||||
QString baseText;
|
QString documentText = document->text(KTextEditor::Range(KTextEditor::Cursor(0, 0), cursor));
|
||||||
|
|
||||||
|
if(m_useInstruct)
|
||||||
|
{
|
||||||
|
context.append(QStringLiteral("### System Prompt\n"));
|
||||||
|
context.append(m_systemPrompt);
|
||||||
|
context.push_back(u'\n');
|
||||||
|
context.append(QStringLiteral("### User Message\n"));
|
||||||
|
context.append(instruction);
|
||||||
|
context.push_back(QStringLiteral("\n### Assistant\n"));
|
||||||
|
}
|
||||||
|
|
||||||
if(!m_useInstruct)
|
|
||||||
baseText = document->text(KTextEditor::Range(KTextEditor::Cursor(0, 0), cursor));
|
|
||||||
else
|
|
||||||
baseText = document->text();
|
|
||||||
if(mime == QStringLiteral("text/x-c++src") || mime == QStringLiteral("text/x-csrc"))
|
if(mime == QStringLiteral("text/x-c++src") || mime == QStringLiteral("text/x-csrc"))
|
||||||
{
|
{
|
||||||
QFileInfo documentFileInfo(document->url().path());
|
QFileInfo documentFileInfo(document->url().path());
|
||||||
QString directory = documentFileInfo.absolutePath();
|
QString directory = documentFileInfo.absolutePath();
|
||||||
QStringList paths = getIncludePaths(baseText);
|
QStringList paths = getIncludePaths(documentText);
|
||||||
qDebug()<<__func__<<"Directory:"<<directory<<"Paths:"<<paths;
|
qDebug()<<__func__<<"Directory:"<<directory<<"Paths:"<<paths;
|
||||||
|
|
||||||
for(QString& path : paths)
|
for(QString& path : paths)
|
||||||
@ -173,7 +185,7 @@ QString KateAiPluginView::assembleContext(QPointer<KTextEditor::Document> docume
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
context.append(baseText);
|
context.append(documentText);
|
||||||
|
|
||||||
return context;
|
return context;
|
||||||
}
|
}
|
||||||
@ -185,15 +197,30 @@ void KateAiPluginView::generate()
|
|||||||
{
|
{
|
||||||
KTextEditor::Cursor cursor = getCurrentCursor();
|
KTextEditor::Cursor cursor = getCurrentCursor();
|
||||||
QPointer<KTextEditor::Document> document = activeDocument();
|
QPointer<KTextEditor::Document> document = activeDocument();
|
||||||
QString text = assembleContext(document, cursor);
|
QString instruction;
|
||||||
|
|
||||||
AiBackend::Request request(text);
|
if(m_useInstruct)
|
||||||
m_ai->generate(request);
|
{
|
||||||
m_requests.insert(request.getId(), {cursor, document});
|
bool ok;
|
||||||
|
instruction = QInputDialog::getMultiLineText(m_mainWindow->activeView(), i18n("Input instruction"),
|
||||||
|
i18n("Instruction"), m_lastInstruct, &ok);
|
||||||
|
if(!ok)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString text = assembleContext(document, cursor, instruction);
|
||||||
|
|
||||||
|
AiBackend::Request request(text, AiBackend::Request::INFERENCE);
|
||||||
|
bool ret = m_ai->generate(request);
|
||||||
|
if(!ret)
|
||||||
|
QMessageBox::warning(m_mainWindow->activeView(), i18n("Failure"),
|
||||||
|
i18n("The Ai backend was unable to process this request"));
|
||||||
|
else
|
||||||
|
m_requests.insert(request.getId(), {cursor, document});
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
QMessageBox box;
|
QMessageBox box(m_mainWindow->activeView());
|
||||||
box.setText(i18n("The AI server is not connected."));
|
box.setText(i18n("The AI server is not connected."));
|
||||||
box.setInformativeText(i18n("would you like to try and reconnect?"));
|
box.setInformativeText(i18n("would you like to try and reconnect?"));
|
||||||
box.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
|
box.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
|
||||||
@ -214,5 +241,20 @@ void KateAiPluginView::setInstruct(bool instruct)
|
|||||||
m_useInstruct = instruct;
|
m_useInstruct = instruct;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void KateAiPluginView::setSystemPrompt(const QString& in)
|
||||||
|
{
|
||||||
|
m_systemPrompt = in;
|
||||||
|
}
|
||||||
|
|
||||||
|
void KateAiPluginView::setAi(QPointer<AiBackend> ai)
|
||||||
|
{
|
||||||
|
m_ai = ai;
|
||||||
|
}
|
||||||
|
|
||||||
|
void KateAiPluginView::setMaxContext(int maxContext)
|
||||||
|
{
|
||||||
|
m_maxContext = maxContext;
|
||||||
|
}
|
||||||
|
|
||||||
#include "kateai.moc"
|
#include "kateai.moc"
|
||||||
#include "moc_kateai.cpp"
|
#include "moc_kateai.cpp"
|
||||||
|
15
kateai.h
15
kateai.h
@ -52,23 +52,28 @@ private:
|
|||||||
|
|
||||||
KTextEditor::MainWindow *m_mainWindow;
|
KTextEditor::MainWindow *m_mainWindow;
|
||||||
inline static QPointer<AiBackend> m_ai;
|
inline static QPointer<AiBackend> m_ai;
|
||||||
bool m_useInstruct = false;
|
inline static bool m_useInstruct = false;
|
||||||
|
inline static QString m_systemPrompt;
|
||||||
|
inline static int m_maxContext;
|
||||||
|
inline static QString m_lastInstruct;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void generate();
|
void generate();
|
||||||
void gotResponse(AiBackend::Response respons);
|
void gotResponse(AiBackend::Response respons);
|
||||||
static QStringList getIncludePaths(const QString& text);
|
static QStringList getIncludePaths(const QString& text);
|
||||||
QString assembleContext(QPointer<KTextEditor::Document> document, const KTextEditor::Cursor& cursor);
|
QString assembleContext(QPointer<KTextEditor::Document> document, const KTextEditor::Cursor& cursor, const QString& instruction = QString());
|
||||||
|
|
||||||
QPointer<KTextEditor::Document> activeDocument() const;
|
QPointer<KTextEditor::Document> activeDocument() const;
|
||||||
KTextEditor::Cursor getCurrentCursor() const;
|
KTextEditor::Cursor getCurrentCursor() const;
|
||||||
QHash<uint32_t, Request> m_requests;
|
QHash<uint32_t, Request> m_requests;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
KateAiPluginView(KateAiPlugin *plugin, KTextEditor::MainWindow *mainwindow, bool instruct = false);
|
KateAiPluginView(KateAiPlugin *plugin, KTextEditor::MainWindow *mainwindow);
|
||||||
~KateAiPluginView() override;
|
~KateAiPluginView() override;
|
||||||
void setInstruct(bool instruct);
|
static void setInstruct(bool instruct);
|
||||||
static void setAi(QPointer<AiBackend> ai){m_ai = ai;}
|
static void setSystemPrompt(const QString& in);
|
||||||
|
static void setMaxContext(int maxContext);
|
||||||
|
static void setAi(QPointer<AiBackend> ai);
|
||||||
|
|
||||||
Q_SIGNAL void reconnect();
|
Q_SIGNAL void reconnect();
|
||||||
};
|
};
|
||||||
|
@ -7,6 +7,9 @@
|
|||||||
#include <QVBoxLayout>
|
#include <QVBoxLayout>
|
||||||
#include <QLabel>
|
#include <QLabel>
|
||||||
#include <qlabel.h>
|
#include <qlabel.h>
|
||||||
|
#include <qradiobutton.h>
|
||||||
|
|
||||||
|
#include "backend.h"
|
||||||
|
|
||||||
KateAiConfigPage::KateAiConfigPage(QWidget *parent, KateAiPlugin *plugin)
|
KateAiConfigPage::KateAiConfigPage(QWidget *parent, KateAiPlugin *plugin)
|
||||||
: KTextEditor::ConfigPage(parent)
|
: KTextEditor::ConfigPage(parent)
|
||||||
@ -15,19 +18,42 @@ KateAiConfigPage::KateAiConfigPage(QWidget *parent, KateAiPlugin *plugin)
|
|||||||
QVBoxLayout* layout = new QVBoxLayout(this);
|
QVBoxLayout* layout = new QVBoxLayout(this);
|
||||||
layout->setContentsMargins(0, 0, 0, 0);
|
layout->setContentsMargins(0, 0, 0, 0);
|
||||||
|
|
||||||
|
std::vector<QString> backends = AiBackend::getAvailableBackendNames();
|
||||||
|
for(const QString& name : backends)
|
||||||
|
cmbxServerType.addItem(name);
|
||||||
|
|
||||||
|
layout->addWidget(&cmbxServerType);
|
||||||
|
|
||||||
QHBoxLayout* lineLayout = new QHBoxLayout(this);
|
QHBoxLayout* lineLayout = new QHBoxLayout(this);
|
||||||
QLabel* lineEditLabel = new QLabel(i18n("Url for the WebSockets ExLlama Ai server:"), this);
|
QLabel* lineEditLabel = new QLabel(i18n("Url for the Ai server:"), this);
|
||||||
lineEditLabel->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed));
|
lineEditLabel->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed));
|
||||||
lineLayout->addWidget(lineEditLabel);
|
lineLayout->addWidget(lineEditLabel);
|
||||||
lineLayout->addWidget(&lineUrl);
|
lineLayout->addWidget(&lineUrl);
|
||||||
layout->addLayout(lineLayout);
|
layout->addLayout(lineLayout);
|
||||||
|
|
||||||
|
QHBoxLayout* contextSpinLayout = new QHBoxLayout(this);
|
||||||
|
QLabel* contextSpinLabel = new QLabel(i18n("Maximum context:"), this);
|
||||||
|
contextSpinLayout->addWidget(contextSpinLabel);
|
||||||
|
contextSpinBox.setMinimum(100);
|
||||||
|
contextSpinBox.setMaximum(32768);
|
||||||
|
contextSpinLayout->addWidget(&contextSpinBox);
|
||||||
|
layout->addLayout(contextSpinLayout);
|
||||||
|
|
||||||
btnCompletion.setText(i18n("Use the Ai to generate a completion"));
|
btnCompletion.setText(i18n("Use the Ai to generate a completion"));
|
||||||
btnInstruct.setText(i18n("Use the Ai to insert a response to a instruction"));
|
btnInstruct.setText(i18n("Use the Ai to insert a response to an instruction"));
|
||||||
layout->addWidget(&btnCompletion);
|
layout->addWidget(&btnCompletion);
|
||||||
layout->addWidget(&btnInstruct);
|
layout->addWidget(&btnInstruct);
|
||||||
|
|
||||||
|
QHBoxLayout* systemPromptLayout = new QHBoxLayout(this);
|
||||||
|
systemPromptLabel.setText(i18n("System Prompt:"));
|
||||||
|
systemPromptLabel.setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed));
|
||||||
|
systemPromptLayout->addWidget(&systemPromptLabel);
|
||||||
|
systemPromptLayout->addWidget(&lineSystemPrompt);
|
||||||
|
layout->addLayout(systemPromptLayout);
|
||||||
layout->addStretch();
|
layout->addStretch();
|
||||||
|
|
||||||
|
connect(&btnInstruct, &QRadioButton::toggled, this, &KateAiConfigPage::instructBtnToggeled);
|
||||||
|
|
||||||
reset();
|
reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -51,6 +77,9 @@ void KateAiConfigPage::apply()
|
|||||||
KConfigGroup config(KSharedConfig::openConfig(), "Ai");
|
KConfigGroup config(KSharedConfig::openConfig(), "Ai");
|
||||||
config.writeEntry("Url", lineUrl.text());
|
config.writeEntry("Url", lineUrl.text());
|
||||||
config.writeEntry("Instruct", btnInstruct.isChecked());
|
config.writeEntry("Instruct", btnInstruct.isChecked());
|
||||||
|
config.writeEntry("SystemPrompt", lineSystemPrompt.text());
|
||||||
|
config.writeEntry("Context", contextSpinBox.value());
|
||||||
|
config.writeEntry("Backend", cmbxServerType.currentText());
|
||||||
|
|
||||||
config.sync();
|
config.sync();
|
||||||
m_plugin->readConfig();
|
m_plugin->readConfig();
|
||||||
@ -59,7 +88,19 @@ void KateAiConfigPage::apply()
|
|||||||
void KateAiConfigPage::reset()
|
void KateAiConfigPage::reset()
|
||||||
{
|
{
|
||||||
KConfigGroup config(KSharedConfig::openConfig(), "Ai");
|
KConfigGroup config(KSharedConfig::openConfig(), "Ai");
|
||||||
lineUrl.setText(config.readEntry("Url", "ws://localhost:8642"));
|
lineSystemPrompt.setText(config.readEntry("SystemPrompt", "ws://localhost:8642"));
|
||||||
|
lineUrl.setText(config.readEntry("Url", "You are an intelligent programming assistant."));
|
||||||
btnInstruct.setChecked(config.readEntry("Instruct", false));
|
btnInstruct.setChecked(config.readEntry("Instruct", false));
|
||||||
btnCompletion.setChecked(!btnInstruct.isChecked());
|
btnCompletion.setChecked(!btnInstruct.isChecked());
|
||||||
|
contextSpinBox.setValue(config.readEntry("Context", 1024));
|
||||||
|
cmbxServerType.setCurrentText(config.readEntry("Backend", "KoboldAI"));
|
||||||
|
|
||||||
|
lineSystemPrompt.setEnabled(btnInstruct.isChecked());
|
||||||
|
systemPromptLabel.setEnabled(btnInstruct.isChecked());
|
||||||
|
}
|
||||||
|
|
||||||
|
void KateAiConfigPage::instructBtnToggeled(bool checked)
|
||||||
|
{
|
||||||
|
lineSystemPrompt.setEnabled(checked);
|
||||||
|
systemPromptLabel.setEnabled(checked);
|
||||||
}
|
}
|
||||||
|
@ -5,16 +5,27 @@
|
|||||||
|
|
||||||
#include <QLineEdit>
|
#include <QLineEdit>
|
||||||
#include <QRadioButton>
|
#include <QRadioButton>
|
||||||
|
#include <QComboBox>
|
||||||
|
#include <QSpinBox>
|
||||||
|
#include <QLabel>
|
||||||
|
|
||||||
class KateAiConfigPage : public KTextEditor::ConfigPage
|
class KateAiConfigPage : public KTextEditor::ConfigPage
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
private:
|
private:
|
||||||
QLineEdit lineUrl;
|
QLineEdit lineUrl;
|
||||||
|
QLabel systemPromptLabel;
|
||||||
|
QLineEdit lineSystemPrompt;
|
||||||
QRadioButton btnCompletion;
|
QRadioButton btnCompletion;
|
||||||
QRadioButton btnInstruct;
|
QRadioButton btnInstruct;
|
||||||
|
QComboBox cmbxServerType;
|
||||||
|
QSpinBox contextSpinBox;
|
||||||
KateAiPlugin* m_plugin;
|
KateAiPlugin* m_plugin;
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
void instructBtnToggeled(bool checked);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit KateAiConfigPage(QWidget *parent = nullptr, KateAiPlugin *plugin = nullptr);
|
explicit KateAiConfigPage(QWidget *parent = nullptr, KateAiPlugin *plugin = nullptr);
|
||||||
~KateAiConfigPage() override
|
~KateAiConfigPage() override
|
||||||
|
Reference in New Issue
Block a user