Skip to content

Commit

Permalink
feat: [aiManager] add interface
Browse files Browse the repository at this point in the history
1.event when LLM changed
2.modelname
3.LLM`s idle state to description LLM can send request or not

Log: as title
  • Loading branch information
LiHua000 authored and deepin-mozart committed Jan 6, 2025
1 parent 542dc99 commit eb9bf5f
Show file tree
Hide file tree
Showing 6 changed files with 135 additions and 24 deletions.
2 changes: 2 additions & 0 deletions src/base/ai/abstractllm.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ class AbstractLLM : public QObject
explicit AbstractLLM(QObject *parent = nullptr);
virtual ~AbstractLLM() {}

virtual QString modelName() const = 0;
virtual QString modelPath() const = 0;
virtual bool checkValid(QString *errStr) = 0;
virtual QJsonObject create(const Conversation &conversation) = 0;
Expand All @@ -37,6 +38,7 @@ class AbstractLLM : public QObject
virtual void cancel() = 0;
virtual void setMaxTokens(int maxToken) = 0;
virtual Conversation *getCurrentConversation() = 0;
virtual bool isIdle() = 0;

signals:
void dataReceived(const QString &data, ResponseState statu);
Expand Down
3 changes: 3 additions & 0 deletions src/common/util/eventdefinitions.h
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,9 @@ OPI_OBJECT(session,
OPI_INTERFACE(sessionRenamed, "oldName", "newName")
OPI_INTERFACE(sessionRemoved, "session")
)
OPI_OBJECT(ai,
OPI_INTERFACE(LLMChanged)
)

struct AnalysedData
{
Expand Down
15 changes: 14 additions & 1 deletion src/plugins/aimanager/aimanager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include "openai/openaicompatiblellm.h"
#include "services/option/optionmanager.h"
#include "option/detailwidget.h"
#include "common/util/eventdefinitions.h"

#include <QMap>

Expand Down Expand Up @@ -83,10 +84,22 @@ void AiManager::removeModel(const LLMInfo &info)

void AiManager::readLLMFromOption()
{
auto currentModels = d->models;
bool changed = false;
d->models.clear();

QMap<QString, QVariant> map = OptionManager::getInstance()->getValue(kCATEGORY_CUSTOMMODELS, kCATEGORY_OPTIONKEY).toMap();
auto LLMs = map.value(kCATEGORY_CUSTOMMODELS);
if (LLMs.toList().size() != currentModels.size())
changed = true;

for (auto llmInfo : LLMs.toList()) {
appendModel(LLMInfo::fromVariantMap(llmInfo.toMap()));
LLMInfo info = LLMInfo::fromVariantMap(llmInfo.toMap());
if (!currentModels.contains(info))
changed = true;
appendModel(info);
}

if (changed)
ai.LLMChanged();
}
124 changes: 101 additions & 23 deletions src/plugins/aimanager/openai/openaicompatibleconversation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,45 +7,104 @@
#include <QJsonDocument>
#include <QRegularExpression>

void mergeFunctionCall(QJsonObject &functionCall, const QJsonObject &delta)
{
if (delta.contains("name")) {
functionCall["name"] = functionCall["name"].toString() + delta.value("name").toString();
}
if (delta.contains("arguments")) {
functionCall["arguments"] = functionCall["arguments"].toString() + delta.value("arguments").toString();
}
}

void mergeToolCallMap(QMap<int, QJsonObject> &toolCallMaps, const QJsonArray &tool_calls)
{
for (const QJsonValue &tool_call : tool_calls) {
const QJsonObject &toolCallObj = tool_call.toObject();
int index = toolCallObj["index"].toInt();

if (!toolCallMaps[index].contains("function")) {
toolCallMaps[index]["function"] = QJsonObject();
}

toolCallMaps[index]["index"] = index;

if (toolCallObj.contains("id")) {
toolCallMaps[index]["id"] = toolCallObj.value("id");
}
if (toolCallObj.contains("type")) {
toolCallMaps[index]["type"] = toolCallObj.value("type");
}

QJsonObject toolFun = toolCallMaps[index]["function"].toObject();

if (const QJsonValue &tmpToolFunVal = toolCallObj.value("function"); !tmpToolFunVal.isUndefined()) {
const QJsonObject &tmpToolFun = tmpToolFunVal.toObject();
if (tmpToolFun.contains("name")) {
toolFun["name"] = toolFun["name"].toString() + tmpToolFun.value("name").toString();
}
if (tmpToolFun.contains("arguments")) {
toolFun["arguments"] = toolFun["arguments"].toString() + tmpToolFun.value("arguments").toString();
}
}

toolCallMaps[index]["function"] = toolFun;
}
}


OpenAiCompatibleConversation::OpenAiCompatibleConversation()
{
}

QJsonObject OpenAiCompatibleConversation::parseContentString(const QString &content)
{
QString deltacontent;

QRegularExpression regex(R"(data:\s*\{(.*)\})");
QRegularExpressionMatchIterator iter = regex.globalMatch(content);
QString finishReason;
QJsonObject functionCall;
QMap<int, QJsonObject> toolCallMaps;

QString finishReason = "";
while (iter.hasNext()) {
QRegularExpressionMatch match = iter.next();
QString matchString = match.captured(0);

int startIndex = matchString.indexOf('{');
int endIndex = matchString.lastIndexOf('}');
if (startIndex < 0 || endIndex <= startIndex) {
continue;
}
QString content = matchString.mid(startIndex, endIndex - startIndex + 1);
QJsonObject j = QJsonDocument::fromJson(content.toUtf8()).object();

if (!j.contains("choices")) {
continue;
}

if (startIndex >= 0 && endIndex > startIndex) {
QString content = matchString.mid(startIndex, endIndex - startIndex + 1);

QJsonObject j = QJsonDocument::fromJson(content.toUtf8()).object();
if (j.contains("choices")) {
const QJsonArray &choices = j["choices"].toArray();
for (auto choice = choices.begin(); choice != choices.end(); choice++) {
const QJsonObject &cj = choice->toObject();
if (cj.contains("finish_reason"))
finishReason = cj["finish_reason"].toString();
if (cj.contains("delta")) {
const QJsonObject &delta = cj["delta"].toObject();
if (delta.contains("content")) {
const QString &deltaData = delta["content"].toString();
deltacontent += deltaData;
}
} else if (cj.contains("text")) {
deltacontent += cj["text"].toString();
}
const QJsonArray &choices = j["choices"].toArray();
for (const QJsonValue &choice : choices) {
const QJsonObject &cj = choice.toObject();

if (cj.contains("finish_reason")) {
finishReason = cj["finish_reason"].toString();
}

if (cj.contains("delta")) {
const QJsonObject &delta = cj["delta"].toObject();

if (delta.contains("content")) {
deltacontent += delta["content"].toString();
}

if (delta.contains("function_call")) {
mergeFunctionCall(functionCall, delta.value("function_call").toObject());
}

if (delta.contains("tool_calls")) {
mergeToolCallMap(toolCallMaps, delta.value("tool_calls").toArray());
}
} else if (cj.contains("text")) {
deltacontent += cj["text"].toString();
}
}
}
Expand All @@ -55,8 +114,27 @@ QJsonObject OpenAiCompatibleConversation::parseContentString(const QString &cont
response["content"] = deltacontent;
}

if (!finishReason.isEmpty())
if (!functionCall.isEmpty() || !toolCallMaps.isEmpty()) {
QJsonObject tools;

if (!functionCall.isEmpty()) {
tools["function_call"] = functionCall;
}

if (!toolCallMaps.isEmpty()) {
QJsonArray toolCalls;
for (const auto &toolCallObj : toolCallMaps) {
toolCalls << toolCallObj;
}
tools["tool_calls"] = toolCalls;
}

response["tools"] = tools;
}

if (!finishReason.isEmpty()) {
response["finish_reason"] = finishReason;
}

return response;
}
Expand Down
13 changes: 13 additions & 0 deletions src/plugins/aimanager/openai/openaicompatiblellm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,11 @@ OpenAiCompatibleLLM::~OpenAiCompatibleLLM()
delete d;
}

QString OpenAiCompatibleLLM::modelName() const
{
return d->modelName;
}

QString OpenAiCompatibleLLM::modelPath() const
{
return d->modelPath;
Expand Down Expand Up @@ -196,6 +201,9 @@ QJsonObject OpenAiCompatibleLLM::create(const Conversation &conversation)

void OpenAiCompatibleLLM::request(const QJsonObject &data)
{
if (d->waitingResponse)
return;

QByteArray body = QJsonDocument(data).toJson();
d->httpResult.clear();
d->waitingResponse = true;
Expand Down Expand Up @@ -339,3 +347,8 @@ void OpenAiCompatibleLLM::setMaxTokens(int maxTokens)
{
d->maxTokens = maxTokens;
}

bool OpenAiCompatibleLLM::isIdle()
{
return !d->waitingResponse;
}
2 changes: 2 additions & 0 deletions src/plugins/aimanager/openai/openaicompatiblellm.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ class OpenAiCompatibleLLM : public AbstractLLM
void setModelPath(const QString &path);
void setApiKey(const QString &apiKey);

QString modelName() const override;
QString modelPath() const override;
bool checkValid(QString *errStr) override;
QJsonObject create(const Conversation &conversation) override;
Expand All @@ -31,6 +32,7 @@ class OpenAiCompatibleLLM : public AbstractLLM
void processResponse(QNetworkReply *reply) override;
void cancel() override;
void setMaxTokens(int maxTokens) override;
bool isIdle() override;

signals:
void requstCancel();
Expand Down

0 comments on commit eb9bf5f

Please sign in to comment.