Browse Source

refactored some TB models for correct open-api schema generation

pull/14929/head
dashevchenko 8 months ago
parent
commit
dca6302146
  1. 14
      application/src/main/java/org/thingsboard/server/config/SwaggerConfiguration.java
  2. 2
      application/src/main/java/org/thingsboard/server/controller/AiModelController.java
  3. 4
      application/src/main/java/org/thingsboard/server/controller/BaseController.java
  4. 29
      application/src/main/java/org/thingsboard/server/controller/CalculatedFieldController.java
  5. 3
      application/src/main/java/org/thingsboard/server/service/ai/AiChatModelServiceImpl.java
  6. 118
      application/src/main/java/org/thingsboard/server/service/ai/Langchain4jChatModelConfigurerImpl.java
  7. 2
      common/data/src/main/java/org/thingsboard/server/common/data/ApiFeature.java
  8. 2
      common/data/src/main/java/org/thingsboard/server/common/data/ai/dto/TbChatRequest.java
  9. 6
      common/data/src/main/java/org/thingsboard/server/common/data/ai/model/AiModelConfig.java
  10. 5
      common/data/src/main/java/org/thingsboard/server/common/data/ai/model/chat/AiChatModelConfig.java
  11. 38
      common/data/src/main/java/org/thingsboard/server/common/data/ai/model/chat/AmazonBedrockChatModelConfig.java
  12. 40
      common/data/src/main/java/org/thingsboard/server/common/data/ai/model/chat/AnthropicChatModelConfig.java
  13. 43
      common/data/src/main/java/org/thingsboard/server/common/data/ai/model/chat/AzureOpenAiChatModelConfig.java
  14. 41
      common/data/src/main/java/org/thingsboard/server/common/data/ai/model/chat/GitHubModelsChatModelConfig.java
  15. 44
      common/data/src/main/java/org/thingsboard/server/common/data/ai/model/chat/GoogleAiGeminiChatModelConfig.java
  16. 43
      common/data/src/main/java/org/thingsboard/server/common/data/ai/model/chat/GoogleVertexAiGeminiChatModelConfig.java
  17. 41
      common/data/src/main/java/org/thingsboard/server/common/data/ai/model/chat/MistralAiChatModelConfig.java
  18. 43
      common/data/src/main/java/org/thingsboard/server/common/data/ai/model/chat/OllamaChatModelConfig.java
  19. 41
      common/data/src/main/java/org/thingsboard/server/common/data/ai/model/chat/OpenAiChatModelConfig.java
  20. 2
      common/data/src/main/java/org/thingsboard/server/common/data/ai/provider/AmazonBedrockProviderConfig.java
  21. 2
      common/data/src/main/java/org/thingsboard/server/common/data/alarm/AlarmComment.java
  22. 4
      common/transport/http/src/main/java/org/thingsboard/server/transport/http/DeviceApiController.java
  23. 3
      rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/RuleEngineAiChatModelService.java
  24. 7
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/ai/TbAiNode.java

14
application/src/main/java/org/thingsboard/server/config/SwaggerConfiguration.java

@ -207,7 +207,7 @@ public class SwaggerConfiguration {
operation.responses(loginResponses);
operation.addTagsItem("login-endpoint");
operation.addTagsItem("Thingsboard");
var pathItem = new PathItem().post(operation);
openAPI.path(LOGIN_ENDPOINT, pathItem);
}
@ -230,7 +230,7 @@ public class SwaggerConfiguration {
operation.responses(loginResponses);
operation.addTagsItem("login-endpoint");
operation.addTagsItem("Thingsboard");
var pathItem = new PathItem().post(operation);
openAPI.path(REFRESH_TOKEN_ENDPOINT, pathItem);
}
@ -272,11 +272,11 @@ public class SwaggerConfiguration {
}
private void addDefaultSchemas(OpenAPI openAPI) {
var jsonNodeSchema = ModelConverters.getInstance().readAllAsResolvedSchema(new AnnotatedType().type(JsonNode.class)).schema;
jsonNodeSchema.setType("any");
//noinspection unchecked
jsonNodeSchema.setExamples(List.of(JacksonUtil.newObjectNode()));
jsonNodeSchema.setDescription("A value representing the any type (object or primitive)");
Schema<?> jsonNodeSchema = new Schema<>()
.type("object")
.description("Arbitrary JSON object or primitive value")
.additionalProperties(true)
.example(JacksonUtil.newObjectNode());
openAPI.getComponents()
.addSchemas("JsonNode", jsonNodeSchema)
.addSchemas("LoginRequest", ModelConverters.getInstance().readAllAsResolvedSchema(new AnnotatedType().type(LoginRequest.class)).schema)

2
application/src/main/java/org/thingsboard/server/controller/AiModelController.java

@ -165,7 +165,7 @@ class AiModelController extends BaseController {
@PostMapping("/chat")
public DeferredResult<TbChatResponse> sendChatRequest(@Valid @RequestBody TbChatRequest tbChatRequest) {
ChatRequest langChainChatRequest = tbChatRequest.toLangChainChatRequest();
AiChatModelConfig<?> chatModelConfig = tbChatRequest.chatModelConfig();
AiChatModelConfig<?, ?> chatModelConfig = tbChatRequest.chatModelConfig();
ListenableFuture<TbChatResponse> future = aiChatModelService.sendChatRequestAsync(chatModelConfig, langChainChatRequest)
.transform(chatResponse -> (TbChatResponse) new TbChatResponse.Success(chatResponse.aiMessage().text()), directExecutor())

4
application/src/main/java/org/thingsboard/server/controller/BaseController.java

@ -18,6 +18,7 @@ package org.thingsboard.server.controller;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.google.common.util.concurrent.ListenableFuture;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.mail.MessagingException;
import jakarta.servlet.ServletOutputStream;
import jakarta.servlet.http.HttpServletResponse;
@ -219,6 +220,9 @@ import static org.thingsboard.server.controller.UserController.YOU_DON_T_HAVE_PE
import static org.thingsboard.server.dao.service.Validator.validateId;
@TbCoreComponent
@Tag(
name = "Thingsboard"
)
public abstract class BaseController {
protected static final String DASHBOARD_ID = "dashboardId";

29
application/src/main/java/org/thingsboard/server/controller/CalculatedFieldController.java

@ -17,6 +17,7 @@ package org.thingsboard.server.controller;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JsonNode;
import io.swagger.v3.oas.annotations.Hidden;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.RequiredArgsConstructor;
@ -154,12 +155,30 @@ public class CalculatedFieldController extends BaseController {
return calculatedField;
}
@Hidden
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN')")
@GetMapping(value = "/{entityType}/{entityId}/calculatedFields", params = {"pageSize", "page"})
public PageData<CalculatedField> getCalculatedFieldsByEntityId(
@PathVariable("entityType") String entityType,
@PathVariable("entityId") String entityIdStr,
@RequestParam int pageSize,
@RequestParam int page,
@RequestParam(required = false) String textSearch,
@RequestParam(required = false) String sortProperty,
@RequestParam(required = false) String sortOrder) throws ThingsboardException {
PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder);
checkParameter("entityId", entityIdStr);
EntityId entityId = EntityIdFactory.getByTypeAndUuid(entityType, entityIdStr);
checkEntityId(entityId, Operation.READ_CALCULATED_FIELD);
return checkNotNull(tbCalculatedFieldService.findAllByTenantIdAndEntityId(entityId, getCurrentUser(), pageLink));
}
@ApiOperation(value = "Get Calculated Fields by Entity Id (getCalculatedFieldsByEntityId)",
notes = "Fetch the Calculated Fields based on the provided Entity Id."
)
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN')")
@GetMapping(value = "/{entityType}/{entityId}/calculatedFields", params = {"pageSize", "page"})
public PageData<CalculatedField> getCalculatedFieldsByEntityId(
@GetMapping(value = "/calculatedField/{entityType}/{entityId}", params = {"pageSize", "page"})
public PageData<CalculatedField> getCalculatedFieldsByEntityIdV2(
@Parameter(description = ENTITY_TYPE_PARAM_DESCRIPTION, required = true, schema = @Schema(defaultValue = "DEVICE")) @PathVariable("entityType") String entityType,
@Parameter(description = ENTITY_ID_PARAM_DESCRIPTION, required = true) @PathVariable("entityId") String entityIdStr,
@Parameter(description = PAGE_SIZE_DESCRIPTION, required = true) @RequestParam int pageSize,
@ -167,11 +186,7 @@ public class CalculatedFieldController extends BaseController {
@Parameter(description = CF_TEXT_SEARCH_DESCRIPTION) @RequestParam(required = false) String textSearch,
@Parameter(description = SORT_PROPERTY_DESCRIPTION, schema = @Schema(allowableValues = {"createdTime", "name"})) @RequestParam(required = false) String sortProperty,
@Parameter(description = SORT_ORDER_DESCRIPTION, schema = @Schema(allowableValues = {"ASC", "DESC"})) @RequestParam(required = false) String sortOrder) throws ThingsboardException {
PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder);
checkParameter("entityId", entityIdStr);
EntityId entityId = EntityIdFactory.getByTypeAndUuid(entityType, entityIdStr);
checkEntityId(entityId, Operation.READ_CALCULATED_FIELD);
return checkNotNull(tbCalculatedFieldService.findAllByTenantIdAndEntityId(entityId, getCurrentUser(), pageLink));
return getCalculatedFieldsByEntityId(entityType, entityIdStr, pageSize, page, textSearch, sortProperty, sortOrder);
}
@ApiOperation(value = "Delete Calculated Field (deleteCalculatedField)",

3
application/src/main/java/org/thingsboard/server/service/ai/AiChatModelServiceImpl.java

@ -29,6 +29,7 @@ import lombok.RequiredArgsConstructor;
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 org.thingsboard.server.common.data.ai.provider.AiProviderConfig;
import java.util.List;
import java.util.stream.Collectors;
@ -41,7 +42,7 @@ class AiChatModelServiceImpl implements AiChatModelService {
private final AiRequestsExecutor aiRequestsExecutor;
@Override
public <C extends AiChatModelConfig<C>> FluentFuture<ChatResponse> sendChatRequestAsync(AiChatModelConfig<C> chatModelConfig, ChatRequest chatRequest) {
public <C extends AiChatModelConfig<C, P>, P extends AiProviderConfig> FluentFuture<ChatResponse> sendChatRequestAsync(AiChatModelConfig<C, P> chatModelConfig, ChatRequest chatRequest) {
ChatModel langChainChatModel = chatModelConfig.configure(chatModelConfigurer);
if (langChainChatModel.provider() == ModelProvider.GITHUB_MODELS) {
chatRequest = prepareGithubChatRequest(chatRequest);

118
application/src/main/java/org/thingsboard/server/service/ai/Langchain4jChatModelConfigurerImpl.java

@ -72,12 +72,12 @@ class Langchain4jChatModelConfigurerImpl implements Langchain4jChatModelConfigur
return OpenAiChatModel.builder()
.baseUrl(chatModelConfig.providerConfig().baseUrl())
.apiKey(chatModelConfig.providerConfig().apiKey())
.modelName(chatModelConfig.modelId())
.temperature(chatModelConfig.temperature())
.topP(chatModelConfig.topP())
.frequencyPenalty(chatModelConfig.frequencyPenalty())
.presencePenalty(chatModelConfig.presencePenalty())
.maxTokens(chatModelConfig.maxOutputTokens())
.modelName(chatModelConfig.getModelId())
.temperature(chatModelConfig.getTemperature())
.topP(chatModelConfig.getTopP())
.frequencyPenalty(chatModelConfig.getFrequencyPenalty())
.presencePenalty(chatModelConfig.getPresencePenalty())
.maxTokens(chatModelConfig.getMaxOutputTokens())
.timeout(toDuration(chatModelConfig.timeoutSeconds()))
.maxRetries(chatModelConfig.maxRetries())
.build();
@ -90,12 +90,12 @@ class Langchain4jChatModelConfigurerImpl implements Langchain4jChatModelConfigur
.endpoint(providerConfig.endpoint())
.serviceVersion(providerConfig.serviceVersion())
.apiKey(providerConfig.apiKey())
.deploymentName(chatModelConfig.modelId())
.temperature(chatModelConfig.temperature())
.topP(chatModelConfig.topP())
.frequencyPenalty(chatModelConfig.frequencyPenalty())
.presencePenalty(chatModelConfig.presencePenalty())
.maxTokens(chatModelConfig.maxOutputTokens())
.deploymentName(chatModelConfig.getModelId())
.temperature(chatModelConfig.getTemperature())
.topP(chatModelConfig.getTopP())
.frequencyPenalty(chatModelConfig.getFrequencyPenalty())
.presencePenalty(chatModelConfig.getPresencePenalty())
.maxTokens(chatModelConfig.getMaxOutputTokens())
.timeout(toDuration(chatModelConfig.timeoutSeconds()))
.maxRetries(chatModelConfig.maxRetries())
.build();
@ -105,13 +105,13 @@ class Langchain4jChatModelConfigurerImpl implements Langchain4jChatModelConfigur
public ChatModel configureChatModel(GoogleAiGeminiChatModelConfig chatModelConfig) {
return GoogleAiGeminiChatModel.builder()
.apiKey(chatModelConfig.providerConfig().apiKey())
.modelName(chatModelConfig.modelId())
.temperature(chatModelConfig.temperature())
.topP(chatModelConfig.topP())
.topK(chatModelConfig.topK())
.frequencyPenalty(chatModelConfig.frequencyPenalty())
.presencePenalty(chatModelConfig.presencePenalty())
.maxOutputTokens(chatModelConfig.maxOutputTokens())
.modelName(chatModelConfig.getModelId())
.temperature(chatModelConfig.getTemperature())
.topP(chatModelConfig.getTopP())
.topK(chatModelConfig.getTopK())
.frequencyPenalty(chatModelConfig.getFrequencyPenalty())
.presencePenalty(chatModelConfig.getPresencePenalty())
.maxOutputTokens(chatModelConfig.getMaxOutputTokens())
.timeout(toDuration(chatModelConfig.timeoutSeconds()))
.maxRetries(chatModelConfig.maxRetries())
.build();
@ -165,28 +165,28 @@ class Langchain4jChatModelConfigurerImpl implements Langchain4jChatModelConfigur
// map model config to generation config
var generationConfigBuilder = GenerationConfig.newBuilder();
if (chatModelConfig.temperature() != null) {
generationConfigBuilder.setTemperature(chatModelConfig.temperature().floatValue());
if (chatModelConfig.getTemperature() != null) {
generationConfigBuilder.setTemperature(chatModelConfig.getTemperature().floatValue());
}
if (chatModelConfig.topP() != null) {
generationConfigBuilder.setTopP(chatModelConfig.topP().floatValue());
if (chatModelConfig.getTopP() != null) {
generationConfigBuilder.setTopP(chatModelConfig.getTopP().floatValue());
}
if (chatModelConfig.topK() != null) {
generationConfigBuilder.setTopK(chatModelConfig.topK());
if (chatModelConfig.getTopK() != null) {
generationConfigBuilder.setTopK(chatModelConfig.getTopK());
}
if (chatModelConfig.frequencyPenalty() != null) {
generationConfigBuilder.setFrequencyPenalty(chatModelConfig.frequencyPenalty().floatValue());
if (chatModelConfig.getFrequencyPenalty() != null) {
generationConfigBuilder.setFrequencyPenalty(chatModelConfig.getFrequencyPenalty().floatValue());
}
if (chatModelConfig.frequencyPenalty() != null) {
generationConfigBuilder.setPresencePenalty(chatModelConfig.frequencyPenalty().floatValue());
if (chatModelConfig.getFrequencyPenalty() != null) {
generationConfigBuilder.setPresencePenalty(chatModelConfig.getFrequencyPenalty().floatValue());
}
if (chatModelConfig.maxOutputTokens() != null) {
generationConfigBuilder.setMaxOutputTokens(chatModelConfig.maxOutputTokens());
if (chatModelConfig.getMaxOutputTokens() != null) {
generationConfigBuilder.setMaxOutputTokens(chatModelConfig.getMaxOutputTokens());
}
var generationConfig = generationConfigBuilder.build();
// construct generative model instance
var generativeModel = new GenerativeModel(chatModelConfig.modelId(), vertexAI).withGenerationConfig(generationConfig);
var generativeModel = new GenerativeModel(chatModelConfig.getModelId(), vertexAI).withGenerationConfig(generationConfig);
return new VertexAiGeminiChatModel(generativeModel, generationConfig, chatModelConfig.maxRetries());
}
@ -203,12 +203,12 @@ class Langchain4jChatModelConfigurerImpl implements Langchain4jChatModelConfigur
public ChatModel configureChatModel(MistralAiChatModelConfig chatModelConfig) {
return MistralAiChatModel.builder()
.apiKey(chatModelConfig.providerConfig().apiKey())
.modelName(chatModelConfig.modelId())
.temperature(chatModelConfig.temperature())
.topP(chatModelConfig.topP())
.frequencyPenalty(chatModelConfig.frequencyPenalty())
.presencePenalty(chatModelConfig.presencePenalty())
.maxTokens(chatModelConfig.maxOutputTokens())
.modelName(chatModelConfig.getModelId())
.temperature(chatModelConfig.getTemperature())
.topP(chatModelConfig.getTopP())
.frequencyPenalty(chatModelConfig.getFrequencyPenalty())
.presencePenalty(chatModelConfig.getPresencePenalty())
.maxTokens(chatModelConfig.getMaxOutputTokens())
.timeout(toDuration(chatModelConfig.timeoutSeconds()))
.maxRetries(chatModelConfig.maxRetries())
.build();
@ -218,11 +218,11 @@ class Langchain4jChatModelConfigurerImpl implements Langchain4jChatModelConfigur
public ChatModel configureChatModel(AnthropicChatModelConfig chatModelConfig) {
return AnthropicChatModel.builder()
.apiKey(chatModelConfig.providerConfig().apiKey())
.modelName(chatModelConfig.modelId())
.temperature(chatModelConfig.temperature())
.topP(chatModelConfig.topP())
.topK(chatModelConfig.topK())
.maxTokens(chatModelConfig.maxOutputTokens())
.modelName(chatModelConfig.getModelId())
.temperature(chatModelConfig.getTemperature())
.topP(chatModelConfig.getTopP())
.topK(chatModelConfig.getTopK())
.maxTokens(chatModelConfig.getMaxOutputTokens())
.timeout(toDuration(chatModelConfig.timeoutSeconds()))
.maxRetries(chatModelConfig.maxRetries())
.build();
@ -242,14 +242,14 @@ class Langchain4jChatModelConfigurerImpl implements Langchain4jChatModelConfigur
.build();
var defaultChatRequestParams = ChatRequestParameters.builder()
.temperature(chatModelConfig.temperature())
.topP(chatModelConfig.topP())
.maxOutputTokens(chatModelConfig.maxOutputTokens())
.temperature(chatModelConfig.getTemperature())
.topP(chatModelConfig.getTopP())
.maxOutputTokens(chatModelConfig.getMaxOutputTokens())
.build();
return BedrockChatModel.builder()
.client(bedrockClient)
.modelId(chatModelConfig.modelId())
.modelId(chatModelConfig.getModelId())
.defaultRequestParameters(defaultChatRequestParams)
.timeout(toDuration(chatModelConfig.timeoutSeconds()))
.maxRetries(chatModelConfig.maxRetries())
@ -260,12 +260,12 @@ class Langchain4jChatModelConfigurerImpl implements Langchain4jChatModelConfigur
public ChatModel configureChatModel(GitHubModelsChatModelConfig chatModelConfig) {
return GitHubModelsChatModel.builder()
.gitHubToken(chatModelConfig.providerConfig().personalAccessToken())
.modelName(chatModelConfig.modelId())
.temperature(chatModelConfig.temperature())
.topP(chatModelConfig.topP())
.frequencyPenalty(chatModelConfig.frequencyPenalty())
.presencePenalty(chatModelConfig.presencePenalty())
.maxTokens(chatModelConfig.maxOutputTokens())
.modelName(chatModelConfig.getModelId())
.temperature(chatModelConfig.getTemperature())
.topP(chatModelConfig.getTopP())
.frequencyPenalty(chatModelConfig.getFrequencyPenalty())
.presencePenalty(chatModelConfig.getPresencePenalty())
.maxTokens(chatModelConfig.getMaxOutputTokens())
.timeout(toDuration(chatModelConfig.timeoutSeconds()))
.maxRetries(chatModelConfig.maxRetries())
.build();
@ -275,12 +275,12 @@ class Langchain4jChatModelConfigurerImpl implements Langchain4jChatModelConfigur
public ChatModel configureChatModel(OllamaChatModelConfig chatModelConfig) {
var builder = OllamaChatModel.builder()
.baseUrl(chatModelConfig.providerConfig().baseUrl())
.modelName(chatModelConfig.modelId())
.temperature(chatModelConfig.temperature())
.topP(chatModelConfig.topP())
.topK(chatModelConfig.topK())
.numCtx(chatModelConfig.contextLength())
.numPredict(chatModelConfig.maxOutputTokens())
.modelName(chatModelConfig.getModelId())
.temperature(chatModelConfig.getTemperature())
.topP(chatModelConfig.getTopP())
.topK(chatModelConfig.getTopK())
.numCtx(chatModelConfig.getContextLength())
.numPredict(chatModelConfig.getContextLength())
.timeout(toDuration(chatModelConfig.timeoutSeconds()))
.maxRetries(chatModelConfig.maxRetries());

2
common/data/src/main/java/org/thingsboard/server/common/data/ApiFeature.java

@ -15,8 +15,10 @@
*/
package org.thingsboard.server.common.data;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Getter;
@Schema(enumAsRef = true)
public enum ApiFeature {
TRANSPORT("transportApiState", "Device API"),
DB("dbApiState", "Telemetry persistence"),

2
common/data/src/main/java/org/thingsboard/server/common/data/ai/dto/TbChatRequest.java

@ -73,7 +73,7 @@ public record TbChatRequest(
}
)
@NotNull @Valid
AiChatModelConfig<?> chatModelConfig
AiChatModelConfig<?, ?> chatModelConfig
) {
public ChatRequest toLangChainChatRequest() {

6
common/data/src/main/java/org/thingsboard/server/common/data/ai/model/AiModelConfig.java

@ -15,6 +15,7 @@
*/
package org.thingsboard.server.common.data.ai.model;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonSubTypes;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import io.swagger.v3.oas.annotations.media.DiscriminatorMapping;
@ -73,7 +74,7 @@ import org.thingsboard.server.common.data.ai.provider.OpenAiProviderConfig;
@DiscriminatorMapping(value = "OLLAMA", schema = OllamaChatModelConfig.class)
}
)
public interface AiModelConfig {
public interface AiModelConfig <T extends AiProviderConfig>{
@Schema(
description = "AI Provider",
@ -112,7 +113,8 @@ public interface AiModelConfig {
@JsonSubTypes.Type(value = GitHubModelsProviderConfig.class, name = "GITHUB_MODELS"),
@JsonSubTypes.Type(value = OllamaProviderConfig.class, name = "OLLAMA")
})
AiProviderConfig providerConfig();
@JsonIgnore
T providerConfig();
AiModelType modelType();

5
common/data/src/main/java/org/thingsboard/server/common/data/ai/model/chat/AiChatModelConfig.java

@ -17,10 +17,13 @@ package org.thingsboard.server.common.data.ai.model.chat;
import com.fasterxml.jackson.annotation.JsonProperty;
import dev.langchain4j.model.chat.ChatModel;
import io.swagger.v3.oas.annotations.media.Schema;
import org.thingsboard.server.common.data.ai.model.AiModelConfig;
import org.thingsboard.server.common.data.ai.model.AiModelType;
import org.thingsboard.server.common.data.ai.provider.AiProviderConfig;
public sealed interface AiChatModelConfig<C extends AiChatModelConfig<C>> extends AiModelConfig
@Schema(description = "AI provider-specific configuration")
public sealed interface AiChatModelConfig<C extends AiChatModelConfig<C, P>, P extends AiProviderConfig> extends AiModelConfig<P>
permits
OpenAiChatModelConfig, AzureOpenAiChatModelConfig, GoogleAiGeminiChatModelConfig,
GoogleVertexAiGeminiChatModelConfig, MistralAiChatModelConfig, AnthropicChatModelConfig,

38
common/data/src/main/java/org/thingsboard/server/common/data/ai/model/chat/AmazonBedrockChatModelConfig.java

@ -16,6 +16,7 @@
package org.thingsboard.server.common.data.ai.model.chat;
import dev.langchain4j.model.chat.ChatModel;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.Valid;
import jakarta.validation.constraints.Max;
import jakarta.validation.constraints.NotBlank;
@ -23,34 +24,51 @@ import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Positive;
import jakarta.validation.constraints.PositiveOrZero;
import lombok.Builder;
import lombok.Data;
import lombok.With;
import org.thingsboard.server.common.data.ai.provider.AiProvider;
import org.thingsboard.server.common.data.ai.provider.AmazonBedrockProviderConfig;
@Schema(description = "Amazon Bedrock chat model configuration")
@Builder
public record AmazonBedrockChatModelConfig(
@NotNull @Valid AmazonBedrockProviderConfig providerConfig,
@NotBlank String modelId,
@PositiveOrZero Double temperature,
@Positive @Max(1) Double topP,
Integer maxOutputTokens,
@With @Positive Integer timeoutSeconds,
@With @PositiveOrZero Integer maxRetries
) implements AiChatModelConfig<AmazonBedrockChatModelConfig> {
@Data
public final class AmazonBedrockChatModelConfig implements AiChatModelConfig<AmazonBedrockChatModelConfig, AmazonBedrockProviderConfig> {
@NotNull @Valid AmazonBedrockProviderConfig providerConfig;
@NotBlank String modelId;
@PositiveOrZero Double temperature;
@Positive @Max(1) Double topP;
Integer maxOutputTokens;
@With @Positive Integer timeoutSeconds;
@With @PositiveOrZero Integer maxRetries;
@Override
public AiProvider provider() {
return AiProvider.AMAZON_BEDROCK;
}
@Override
public AmazonBedrockProviderConfig providerConfig() {
return providerConfig;
}
@Override
public ChatModel configure(Langchain4jChatModelConfigurer configurer) {
return configurer.configureChatModel(this);
}
@Override
public Integer timeoutSeconds() {
return timeoutSeconds;
}
@Override
public Integer maxRetries() {
return maxRetries;
}
@Override
public boolean supportsJsonMode() {
return false;
}
}

40
common/data/src/main/java/org/thingsboard/server/common/data/ai/model/chat/AnthropicChatModelConfig.java

@ -16,6 +16,7 @@
package org.thingsboard.server.common.data.ai.model.chat;
import dev.langchain4j.model.chat.ChatModel;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.Valid;
import jakarta.validation.constraints.Max;
import jakarta.validation.constraints.NotBlank;
@ -23,32 +24,51 @@ import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Positive;
import jakarta.validation.constraints.PositiveOrZero;
import lombok.Builder;
import lombok.Data;
import lombok.With;
import org.thingsboard.server.common.data.ai.provider.AiProvider;
import org.thingsboard.server.common.data.ai.provider.AnthropicProviderConfig;
@Schema()
@Builder
public record AnthropicChatModelConfig(
@NotNull @Valid AnthropicProviderConfig providerConfig,
@NotBlank String modelId,
@PositiveOrZero Double temperature,
@Positive @Max(1) Double topP,
@PositiveOrZero Integer topK,
Integer maxOutputTokens,
@With @Positive Integer timeoutSeconds,
@With @PositiveOrZero Integer maxRetries
) implements AiChatModelConfig<AnthropicChatModelConfig> {
@Data
public final class AnthropicChatModelConfig implements AiChatModelConfig<AnthropicChatModelConfig, AnthropicProviderConfig> {
@NotNull @Valid AnthropicProviderConfig providerConfig;
@NotBlank String modelId;
@PositiveOrZero Double temperature;
@Positive @Max(1) Double topP;
@PositiveOrZero Integer topK;
Integer maxOutputTokens;
@With
@Positive Integer timeoutSeconds;
@With
@PositiveOrZero Integer maxRetries;
@Override
public AiProvider provider() {
return AiProvider.ANTHROPIC;
}
@Override
public AnthropicProviderConfig providerConfig() {
return providerConfig;
}
@Override
public ChatModel configure(Langchain4jChatModelConfigurer configurer) {
return configurer.configureChatModel(this);
}
@Override
public Integer timeoutSeconds() {
return timeoutSeconds;
}
@Override
public Integer maxRetries() {
return maxRetries;
}
@Override
public boolean supportsJsonMode() {
return false;

43
common/data/src/main/java/org/thingsboard/server/common/data/ai/model/chat/AzureOpenAiChatModelConfig.java

@ -16,6 +16,7 @@
package org.thingsboard.server.common.data.ai.model.chat;
import dev.langchain4j.model.chat.ChatModel;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.Valid;
import jakarta.validation.constraints.Max;
import jakarta.validation.constraints.NotBlank;
@ -23,33 +24,53 @@ import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Positive;
import jakarta.validation.constraints.PositiveOrZero;
import lombok.Builder;
import lombok.Data;
import lombok.With;
import org.thingsboard.server.common.data.ai.provider.AiProvider;
import org.thingsboard.server.common.data.ai.provider.AzureOpenAiProviderConfig;
@Schema()
@Builder
public record AzureOpenAiChatModelConfig(
@NotNull @Valid AzureOpenAiProviderConfig providerConfig,
@NotBlank String modelId,
@PositiveOrZero Double temperature,
@Positive @Max(1) Double topP,
Double frequencyPenalty,
Double presencePenalty,
Integer maxOutputTokens,
@With @Positive Integer timeoutSeconds,
@With @PositiveOrZero Integer maxRetries
) implements AiChatModelConfig<AzureOpenAiChatModelConfig> {
@Data
public final class AzureOpenAiChatModelConfig implements AiChatModelConfig<AzureOpenAiChatModelConfig, AzureOpenAiProviderConfig> {
@NotNull @Valid AzureOpenAiProviderConfig providerConfig;
@NotBlank String modelId;
@PositiveOrZero Double temperature;
@Positive @Max(1) Double topP;
Double frequencyPenalty;
Double presencePenalty;
Integer maxOutputTokens;
@With
@Positive Integer timeoutSeconds;
@With
@PositiveOrZero Integer maxRetries;
@Override
public AiProvider provider() {
return AiProvider.AZURE_OPENAI;
}
@Override
public AzureOpenAiProviderConfig providerConfig() {
return providerConfig;
}
@Override
public ChatModel configure(Langchain4jChatModelConfigurer configurer) {
return configurer.configureChatModel(this);
}
@Override
public Integer timeoutSeconds() {
return timeoutSeconds;
}
@Override
public Integer maxRetries() {
return maxRetries;
}
@Override
public boolean supportsJsonMode() {
return true;

41
common/data/src/main/java/org/thingsboard/server/common/data/ai/model/chat/GitHubModelsChatModelConfig.java

@ -16,6 +16,7 @@
package org.thingsboard.server.common.data.ai.model.chat;
import dev.langchain4j.model.chat.ChatModel;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.Valid;
import jakarta.validation.constraints.Max;
import jakarta.validation.constraints.NotBlank;
@ -23,33 +24,51 @@ import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Positive;
import jakarta.validation.constraints.PositiveOrZero;
import lombok.Builder;
import lombok.Data;
import lombok.With;
import org.thingsboard.server.common.data.ai.provider.AiProvider;
import org.thingsboard.server.common.data.ai.provider.GitHubModelsProviderConfig;
@Schema()
@Builder
public record GitHubModelsChatModelConfig(
@NotNull @Valid GitHubModelsProviderConfig providerConfig,
@NotBlank String modelId,
@PositiveOrZero Double temperature,
@Positive @Max(1) Double topP,
Double frequencyPenalty,
Double presencePenalty,
Integer maxOutputTokens,
@With @Positive Integer timeoutSeconds,
@With @PositiveOrZero Integer maxRetries
) implements AiChatModelConfig<GitHubModelsChatModelConfig> {
@Data
public final class GitHubModelsChatModelConfig implements AiChatModelConfig<GitHubModelsChatModelConfig, GitHubModelsProviderConfig> {
@NotNull @Valid GitHubModelsProviderConfig providerConfig;
@NotBlank String modelId;
@PositiveOrZero Double temperature;
@Positive @Max(1) Double topP;
Double frequencyPenalty;
Double presencePenalty;
Integer maxOutputTokens;
@With @Positive Integer timeoutSeconds;
@With @PositiveOrZero Integer maxRetries;
@Override
public AiProvider provider() {
return AiProvider.GITHUB_MODELS;
}
@Override
public GitHubModelsProviderConfig providerConfig() {
return providerConfig;
}
@Override
public ChatModel configure(Langchain4jChatModelConfigurer configurer) {
return configurer.configureChatModel(this);
}
@Override
public Integer timeoutSeconds() {
return timeoutSeconds;
}
@Override
public Integer maxRetries() {
return maxRetries;
}
@Override
public boolean supportsJsonMode() {
return false;

44
common/data/src/main/java/org/thingsboard/server/common/data/ai/model/chat/GoogleAiGeminiChatModelConfig.java

@ -15,7 +15,9 @@
*/
package org.thingsboard.server.common.data.ai.model.chat;
import com.fasterxml.jackson.annotation.JsonTypeName;
import dev.langchain4j.model.chat.ChatModel;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.Valid;
import jakarta.validation.constraints.Max;
import jakarta.validation.constraints.NotBlank;
@ -23,34 +25,52 @@ import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Positive;
import jakarta.validation.constraints.PositiveOrZero;
import lombok.Builder;
import lombok.Data;
import lombok.With;
import org.thingsboard.server.common.data.ai.provider.AiProvider;
import org.thingsboard.server.common.data.ai.provider.GoogleAiGeminiProviderConfig;
@Schema()
@JsonTypeName("GOOGLE_AI_GEMINI")
@Builder
public record GoogleAiGeminiChatModelConfig(
@NotNull @Valid GoogleAiGeminiProviderConfig providerConfig,
@NotBlank String modelId,
@PositiveOrZero Double temperature,
@Positive @Max(1) Double topP,
@PositiveOrZero Integer topK,
Double frequencyPenalty,
Double presencePenalty,
Integer maxOutputTokens,
@With @Positive Integer timeoutSeconds,
@With @PositiveOrZero Integer maxRetries
) implements AiChatModelConfig<GoogleAiGeminiChatModelConfig> {
@Data
public final class GoogleAiGeminiChatModelConfig implements AiChatModelConfig<GoogleAiGeminiChatModelConfig, GoogleAiGeminiProviderConfig> {
@NotNull @Valid GoogleAiGeminiProviderConfig providerConfig;
@NotBlank String modelId;
@PositiveOrZero Double temperature;
@Positive @Max(1) Double topP;
@PositiveOrZero Integer topK;
Double frequencyPenalty;
Double presencePenalty;
Integer maxOutputTokens;
@With @Positive Integer timeoutSeconds;
@With @PositiveOrZero Integer maxRetries;
@Override
public AiProvider provider() {
return AiProvider.GOOGLE_AI_GEMINI;
}
@Override
public GoogleAiGeminiProviderConfig providerConfig() {
return providerConfig;
}
@Override
public ChatModel configure(Langchain4jChatModelConfigurer configurer) {
return configurer.configureChatModel(this);
}
@Override
public Integer timeoutSeconds() {
return timeoutSeconds;
}
@Override
public Integer maxRetries() {
return maxRetries;
}
@Override
public boolean supportsJsonMode() {
return true;

43
common/data/src/main/java/org/thingsboard/server/common/data/ai/model/chat/GoogleVertexAiGeminiChatModelConfig.java

@ -16,6 +16,7 @@
package org.thingsboard.server.common.data.ai.model.chat;
import dev.langchain4j.model.chat.ChatModel;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.Valid;
import jakarta.validation.constraints.Max;
import jakarta.validation.constraints.NotBlank;
@ -23,34 +24,52 @@ import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Positive;
import jakarta.validation.constraints.PositiveOrZero;
import lombok.Builder;
import lombok.Data;
import lombok.With;
import org.thingsboard.server.common.data.ai.provider.AiProvider;
import org.thingsboard.server.common.data.ai.provider.GoogleVertexAiGeminiProviderConfig;
@Schema()
@Builder
public record GoogleVertexAiGeminiChatModelConfig(
@NotNull @Valid GoogleVertexAiGeminiProviderConfig providerConfig,
@NotBlank String modelId,
@PositiveOrZero Double temperature,
@Positive @Max(1) Double topP,
@PositiveOrZero Integer topK,
Double frequencyPenalty,
Double presencePenalty,
Integer maxOutputTokens,
@With @Positive Integer timeoutSeconds,
@With @PositiveOrZero Integer maxRetries
) implements AiChatModelConfig<GoogleVertexAiGeminiChatModelConfig> {
@Data
public final class GoogleVertexAiGeminiChatModelConfig implements AiChatModelConfig<GoogleVertexAiGeminiChatModelConfig, GoogleVertexAiGeminiProviderConfig> {
@NotNull @Valid GoogleVertexAiGeminiProviderConfig providerConfig;
@NotBlank String modelId;
@PositiveOrZero Double temperature;
@Positive @Max(1) Double topP;
@PositiveOrZero Integer topK;
Double frequencyPenalty;
Double presencePenalty;
Integer maxOutputTokens;
@With @Positive Integer timeoutSeconds;
@With @PositiveOrZero Integer maxRetries;
@Override
public AiProvider provider() {
return AiProvider.GOOGLE_VERTEX_AI_GEMINI;
}
@Override
public GoogleVertexAiGeminiProviderConfig providerConfig() {
return providerConfig;
}
@Override
public ChatModel configure(Langchain4jChatModelConfigurer configurer) {
return configurer.configureChatModel(this);
}
@Override
public Integer timeoutSeconds() {
return timeoutSeconds;
}
@Override
public Integer maxRetries() {
return maxRetries;
}
@Override
public boolean supportsJsonMode() {
return true;

41
common/data/src/main/java/org/thingsboard/server/common/data/ai/model/chat/MistralAiChatModelConfig.java

@ -16,6 +16,7 @@
package org.thingsboard.server.common.data.ai.model.chat;
import dev.langchain4j.model.chat.ChatModel;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.Valid;
import jakarta.validation.constraints.Max;
import jakarta.validation.constraints.NotBlank;
@ -23,33 +24,51 @@ import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Positive;
import jakarta.validation.constraints.PositiveOrZero;
import lombok.Builder;
import lombok.Data;
import lombok.With;
import org.thingsboard.server.common.data.ai.provider.AiProvider;
import org.thingsboard.server.common.data.ai.provider.MistralAiProviderConfig;
@Schema()
@Builder
public record MistralAiChatModelConfig(
@NotNull @Valid MistralAiProviderConfig providerConfig,
@NotBlank String modelId,
@PositiveOrZero Double temperature,
@Positive @Max(1) Double topP,
Double frequencyPenalty,
Double presencePenalty,
Integer maxOutputTokens,
@With @Positive Integer timeoutSeconds,
@With @PositiveOrZero Integer maxRetries
) implements AiChatModelConfig<MistralAiChatModelConfig> {
@Data
public final class MistralAiChatModelConfig implements AiChatModelConfig<MistralAiChatModelConfig, MistralAiProviderConfig> {
@NotNull @Valid MistralAiProviderConfig providerConfig;
@NotBlank String modelId;
@PositiveOrZero Double temperature;
@Positive @Max(1) Double topP;
Double frequencyPenalty;
Double presencePenalty;
Integer maxOutputTokens;
@With @Positive Integer timeoutSeconds;
@With @PositiveOrZero Integer maxRetries;
@Override
public AiProvider provider() {
return AiProvider.MISTRAL_AI;
}
@Override
public MistralAiProviderConfig providerConfig() {
return providerConfig;
}
@Override
public ChatModel configure(Langchain4jChatModelConfigurer configurer) {
return configurer.configureChatModel(this);
}
@Override
public Integer timeoutSeconds() {
return timeoutSeconds;
}
@Override
public Integer maxRetries() {
return maxRetries;
}
@Override
public boolean supportsJsonMode() {
return true;

43
common/data/src/main/java/org/thingsboard/server/common/data/ai/model/chat/OllamaChatModelConfig.java

@ -16,6 +16,7 @@
package org.thingsboard.server.common.data.ai.model.chat;
import dev.langchain4j.model.chat.ChatModel;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.Valid;
import jakarta.validation.constraints.Max;
import jakarta.validation.constraints.NotBlank;
@ -23,33 +24,53 @@ import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Positive;
import jakarta.validation.constraints.PositiveOrZero;
import lombok.Builder;
import lombok.Data;
import lombok.With;
import org.thingsboard.server.common.data.ai.provider.AiProvider;
import org.thingsboard.server.common.data.ai.provider.OllamaProviderConfig;
@Schema()
@Builder
public record OllamaChatModelConfig(
@NotNull @Valid OllamaProviderConfig providerConfig,
@NotBlank String modelId,
@PositiveOrZero Double temperature,
@Positive @Max(1) Double topP,
@PositiveOrZero Integer topK,
Integer contextLength,
Integer maxOutputTokens,
@With @Positive Integer timeoutSeconds,
@With @PositiveOrZero Integer maxRetries
) implements AiChatModelConfig<OllamaChatModelConfig> {
@Data
public final class OllamaChatModelConfig implements AiChatModelConfig<OllamaChatModelConfig, OllamaProviderConfig> {
@NotNull @Valid OllamaProviderConfig providerConfig;
@NotBlank String modelId;
@PositiveOrZero Double temperature;
@Positive @Max(1) Double topP;
@PositiveOrZero Integer topK;
Integer contextLength;
Integer maxOutputTokens;
@With
@Positive Integer timeoutSeconds;
@With
@PositiveOrZero Integer maxRetries;
@Override
public AiProvider provider() {
return AiProvider.OLLAMA;
}
@Override
public OllamaProviderConfig providerConfig() {
return providerConfig;
}
@Override
public ChatModel configure(Langchain4jChatModelConfigurer configurer) {
return configurer.configureChatModel(this);
}
@Override
public Integer timeoutSeconds() {
return timeoutSeconds;
}
@Override
public Integer maxRetries() {
return maxRetries;
}
@Override
public boolean supportsJsonMode() {
return true;

41
common/data/src/main/java/org/thingsboard/server/common/data/ai/model/chat/OpenAiChatModelConfig.java

@ -16,6 +16,7 @@
package org.thingsboard.server.common.data.ai.model.chat;
import dev.langchain4j.model.chat.ChatModel;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.Valid;
import jakarta.validation.constraints.Max;
import jakarta.validation.constraints.NotBlank;
@ -23,33 +24,51 @@ import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Positive;
import jakarta.validation.constraints.PositiveOrZero;
import lombok.Builder;
import lombok.Data;
import lombok.With;
import org.thingsboard.server.common.data.ai.provider.AiProvider;
import org.thingsboard.server.common.data.ai.provider.OpenAiProviderConfig;
@Schema()
@Builder
public record OpenAiChatModelConfig(
@NotNull @Valid OpenAiProviderConfig providerConfig,
@NotBlank String modelId,
@PositiveOrZero Double temperature,
@Positive @Max(1) Double topP,
Double frequencyPenalty,
Double presencePenalty,
Integer maxOutputTokens,
@With @Positive Integer timeoutSeconds,
@With @PositiveOrZero Integer maxRetries
) implements AiChatModelConfig<OpenAiChatModelConfig> {
@Data
public final class OpenAiChatModelConfig implements AiChatModelConfig<OpenAiChatModelConfig, OpenAiProviderConfig> {
@NotNull @Valid OpenAiProviderConfig providerConfig;
@NotBlank String modelId;
@PositiveOrZero Double temperature;
@Positive @Max(1) Double topP;
Double frequencyPenalty;
Double presencePenalty;
Integer maxOutputTokens;
@With @Positive Integer timeoutSeconds;
@With @PositiveOrZero Integer maxRetries;
@Override
public AiProvider provider() {
return AiProvider.OPENAI;
}
@Override
public OpenAiProviderConfig providerConfig() {
return providerConfig;
}
@Override
public ChatModel configure(Langchain4jChatModelConfigurer configurer) {
return configurer.configureChatModel(this);
}
@Override
public Integer timeoutSeconds() {
return timeoutSeconds;
}
@Override
public Integer maxRetries() {
return maxRetries;
}
@Override
public boolean supportsJsonMode() {
return true;

2
common/data/src/main/java/org/thingsboard/server/common/data/ai/provider/AmazonBedrockProviderConfig.java

@ -15,8 +15,10 @@
*/
package org.thingsboard.server.common.data.ai.provider;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotNull;
@Schema(description = "Amazon Bedrock AI provider configuration")
public record AmazonBedrockProviderConfig(
@NotNull String region,
@NotNull String accessKeyId,

2
common/data/src/main/java/org/thingsboard/server/common/data/alarm/AlarmComment.java

@ -47,7 +47,7 @@ public class AlarmComment extends BaseData<AlarmCommentId> implements HasName {
private UserId userId;
@Schema(description = "Defines origination of comment. System type means comment was created by TB. OTHER type means comment was created by user.", example = "SYSTEM/OTHER", accessMode = Schema.AccessMode.READ_ONLY)
private AlarmCommentType type;
@Schema(description = "JSON object with text of comment.", type = "object")
@Schema(description = "JSON object with text of comment.", implementation = JsonNode.class)
@NoXss
@Length(fieldName = "comment", max = 10000)
@EqualsAndHashCode.Include

4
common/transport/http/src/main/java/org/thingsboard/server/transport/http/DeviceApiController.java

@ -24,6 +24,7 @@ import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
@ -86,6 +87,9 @@ import java.util.function.Consumer;
@ConditionalOnExpression("'${service.type:null}'=='tb-transport' || ('${service.type:null}'=='monolith' && '${transport.api_enabled:true}'=='true' && '${transport.http.enabled}'=='true')")
@RequestMapping("/api/v1")
@Slf4j
@Tag(
name = "Thingsboard"
)
public class DeviceApiController implements TbTransportService {
private static final String MARKDOWN_CODE_BLOCK_START = "\n\n```json\n";

3
rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/RuleEngineAiChatModelService.java

@ -19,9 +19,10 @@ import com.google.common.util.concurrent.FluentFuture;
import dev.langchain4j.model.chat.request.ChatRequest;
import dev.langchain4j.model.chat.response.ChatResponse;
import org.thingsboard.server.common.data.ai.model.chat.AiChatModelConfig;
import org.thingsboard.server.common.data.ai.provider.AiProviderConfig;
public interface RuleEngineAiChatModelService {
<C extends AiChatModelConfig<C>> FluentFuture<ChatResponse> sendChatRequestAsync(AiChatModelConfig<C> chatModelConfig, ChatRequest chatRequest);
<C extends AiChatModelConfig<C, P>, P extends AiProviderConfig> FluentFuture<ChatResponse> sendChatRequestAsync(AiChatModelConfig<C, P> chatModelConfig, ChatRequest chatRequest);
}

7
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/ai/TbAiNode.java

@ -48,6 +48,7 @@ import org.thingsboard.server.common.data.TbResourceInfo;
import org.thingsboard.server.common.data.ai.AiModel;
import org.thingsboard.server.common.data.ai.model.AiModelType;
import org.thingsboard.server.common.data.ai.model.chat.AiChatModelConfig;
import org.thingsboard.server.common.data.ai.provider.AiProviderConfig;
import org.thingsboard.server.common.data.id.AiModelId;
import org.thingsboard.server.common.data.id.TbResourceId;
import org.thingsboard.server.common.data.id.TenantId;
@ -126,7 +127,7 @@ public final class TbAiNode extends TbAbstractExternalNode implements TbNode {
if (modelType != AiModelType.CHAT) {
throw new TbNodeException("[" + ctx.getTenantId() + "] AI model with ID: [" + modelId + "] must be of type CHAT, but was " + modelType, true);
}
AiChatModelConfig<?> chatModelConfig = (AiChatModelConfig<?>) model.getConfiguration();
AiChatModelConfig<?, ?> chatModelConfig = (AiChatModelConfig<?, ?>) model.getConfiguration();
if (isJsonModeConfigured(config)) {
if (!chatModelConfig.supportsJsonMode()) {
throw new TbNodeException("[" + ctx.getTenantId() + "] AI model with ID: [" + modelId + "] does not support '" + config.getResponseFormat().type() + "' response format", true);
@ -218,7 +219,7 @@ public final class TbAiNode extends TbAbstractExternalNode implements TbNode {
}, directExecutor());
}
private <C extends AiChatModelConfig<C>> FluentFuture<ChatResponse> sendChatRequestAsync(TbContext ctx, ChatRequest chatRequest) {
private <C extends AiChatModelConfig<C, P>, P extends AiProviderConfig> FluentFuture<ChatResponse> sendChatRequestAsync(TbContext ctx, ChatRequest chatRequest) {
return ctx.getAiModelService().findAiModelByTenantIdAndIdAsync(ctx.getTenantId(), modelId).transformAsync(modelOpt -> {
if (modelOpt.isEmpty()) {
throw new NoSuchElementException("[" + ctx.getTenantId() + "] AI model with ID: [" + modelId + "] was not found");
@ -230,7 +231,7 @@ public final class TbAiNode extends TbAbstractExternalNode implements TbNode {
}
@SuppressWarnings("unchecked")
AiChatModelConfig<C> chatModelConfig = (AiChatModelConfig<C>) model.getConfiguration();
AiChatModelConfig<C, P> chatModelConfig = (AiChatModelConfig<C, P>) model.getConfiguration();
chatModelConfig = chatModelConfig
.withTimeoutSeconds(timeoutSeconds)

Loading…
Cancel
Save