From 873dcabb4794b107d348ca23212968bdbe44bf6a Mon Sep 17 00:00:00 2001 From: dashevchenko Date: Mon, 13 Oct 2025 16:05:55 +0300 Subject: [PATCH 1/3] fixed file attaching for Github AI models --- .../service/ai/AiChatModelServiceImpl.java | 47 +++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/application/src/main/java/org/thingsboard/server/service/ai/AiChatModelServiceImpl.java b/application/src/main/java/org/thingsboard/server/service/ai/AiChatModelServiceImpl.java index d6252f57a6..78c0b77f40 100644 --- a/application/src/main/java/org/thingsboard/server/service/ai/AiChatModelServiceImpl.java +++ b/application/src/main/java/org/thingsboard/server/service/ai/AiChatModelServiceImpl.java @@ -16,6 +16,11 @@ package org.thingsboard.server.service.ai; import com.google.common.util.concurrent.FluentFuture; +import dev.langchain4j.data.message.ChatMessage; +import dev.langchain4j.data.message.Content; +import dev.langchain4j.data.message.TextContent; +import dev.langchain4j.data.message.UserMessage; +import dev.langchain4j.model.ModelProvider; import dev.langchain4j.model.chat.ChatModel; import dev.langchain4j.model.chat.request.ChatRequest; import dev.langchain4j.model.chat.response.ChatResponse; @@ -24,6 +29,9 @@ import org.springframework.stereotype.Service; import org.thingsboard.server.common.data.ai.model.chat.AiChatModelConfig; import org.thingsboard.server.common.data.ai.model.chat.Langchain4jChatModelConfigurer; +import java.util.List; +import java.util.stream.Collectors; + @Service @RequiredArgsConstructor class AiChatModelServiceImpl implements AiChatModelService { @@ -34,7 +42,46 @@ class AiChatModelServiceImpl implements AiChatModelService { @Override public > FluentFuture sendChatRequestAsync(AiChatModelConfig chatModelConfig, ChatRequest chatRequest) { ChatModel langChainChatModel = chatModelConfig.configure(chatModelConfigurer); + if (langChainChatModel.provider() == ModelProvider.GITHUB_MODELS) { + chatRequest = prepareGithubChatRequest(chatRequest); + } return aiRequestsExecutor.sendChatRequestAsync(langChainChatModel, chatRequest); } + private ChatRequest prepareGithubChatRequest(ChatRequest chatRequest) { + List messages = chatRequest.messages().stream() + .map(this::escapeIfUserMessage) + .collect(Collectors.toList()); + + return ChatRequest.builder() + .messages(messages) + .responseFormat(chatRequest.responseFormat()) + .build(); + } + + private ChatMessage escapeIfUserMessage(ChatMessage message) { + if (message instanceof UserMessage userMessage) { + List newContents = userMessage.contents().stream() + .map(this::escapeContent) + .collect(Collectors.toList()); + + return UserMessage.from(newContents); + } + return message; + } + + private Content escapeContent(Content content) { + if (content instanceof TextContent txt) { + return new TextContent(escapeWhitespace(txt.text())); + } + return content; + } + + private String escapeWhitespace(String text) { + return text + .replace("\n", "\\n") + .replace("\r", "\\r") + .replace("\t", "\\t"); + } + } From 6bb7dce150246d0fa4625d235f2234dd5952b854 Mon Sep 17 00:00:00 2001 From: dashevchenko Date: Mon, 13 Oct 2025 16:08:12 +0300 Subject: [PATCH 2/3] refactoting --- .../thingsboard/server/service/ai/AiChatModelServiceImpl.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/service/ai/AiChatModelServiceImpl.java b/application/src/main/java/org/thingsboard/server/service/ai/AiChatModelServiceImpl.java index 78c0b77f40..29d4a148fd 100644 --- a/application/src/main/java/org/thingsboard/server/service/ai/AiChatModelServiceImpl.java +++ b/application/src/main/java/org/thingsboard/server/service/ai/AiChatModelServiceImpl.java @@ -72,12 +72,12 @@ class AiChatModelServiceImpl implements AiChatModelService { private Content escapeContent(Content content) { if (content instanceof TextContent txt) { - return new TextContent(escapeWhitespace(txt.text())); + return new TextContent(escapeControlChars(txt.text())); } return content; } - private String escapeWhitespace(String text) { + private String escapeControlChars(String text) { return text .replace("\n", "\\n") .replace("\r", "\\r") From d14466459d70cbef19caa7aa1ea6c127583f6c04 Mon Sep 17 00:00:00 2001 From: dashevchenko Date: Mon, 13 Oct 2025 16:35:57 +0300 Subject: [PATCH 3/3] refactoring --- .../service/ai/AiChatModelServiceImpl.java | 17 ++++++----------- .../server/common/data/StringUtils.java | 7 +++++++ 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/service/ai/AiChatModelServiceImpl.java b/application/src/main/java/org/thingsboard/server/service/ai/AiChatModelServiceImpl.java index 29d4a148fd..c1829cbf84 100644 --- a/application/src/main/java/org/thingsboard/server/service/ai/AiChatModelServiceImpl.java +++ b/application/src/main/java/org/thingsboard/server/service/ai/AiChatModelServiceImpl.java @@ -32,6 +32,8 @@ import org.thingsboard.server.common.data.ai.model.chat.Langchain4jChatModelConf import java.util.List; import java.util.stream.Collectors; +import static org.thingsboard.server.common.data.StringUtils.escapeControlChars; + @Service @RequiredArgsConstructor class AiChatModelServiceImpl implements AiChatModelService { @@ -50,7 +52,7 @@ class AiChatModelServiceImpl implements AiChatModelService { private ChatRequest prepareGithubChatRequest(ChatRequest chatRequest) { List messages = chatRequest.messages().stream() - .map(this::escapeIfUserMessage) + .map(this::prepareUserMessage) .collect(Collectors.toList()); return ChatRequest.builder() @@ -59,10 +61,10 @@ class AiChatModelServiceImpl implements AiChatModelService { .build(); } - private ChatMessage escapeIfUserMessage(ChatMessage message) { + private ChatMessage prepareUserMessage(ChatMessage message) { if (message instanceof UserMessage userMessage) { List newContents = userMessage.contents().stream() - .map(this::escapeContent) + .map(this::prepareContent) .collect(Collectors.toList()); return UserMessage.from(newContents); @@ -70,18 +72,11 @@ class AiChatModelServiceImpl implements AiChatModelService { return message; } - private Content escapeContent(Content content) { + private Content prepareContent(Content content) { if (content instanceof TextContent txt) { return new TextContent(escapeControlChars(txt.text())); } return content; } - private String escapeControlChars(String text) { - return text - .replace("\n", "\\n") - .replace("\r", "\\r") - .replace("\t", "\\t"); - } - } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/StringUtils.java b/common/data/src/main/java/org/thingsboard/server/common/data/StringUtils.java index cbc881d72f..2b8b631027 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/StringUtils.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/StringUtils.java @@ -275,4 +275,11 @@ public class StringUtils { return result; } + public static String escapeControlChars(String text) { + return text + .replace("\n", "\\n") + .replace("\r", "\\r") + .replace("\t", "\\t"); + } + }