diff --git a/application/src/main/java/org/thingsboard/server/config/SwaggerConfiguration.java b/application/src/main/java/org/thingsboard/server/config/SwaggerConfiguration.java index 658029a2fe..d4141c704c 100644 --- a/application/src/main/java/org/thingsboard/server/config/SwaggerConfiguration.java +++ b/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) diff --git a/application/src/main/java/org/thingsboard/server/controller/AiModelController.java b/application/src/main/java/org/thingsboard/server/controller/AiModelController.java index b5780405b1..4c09f84523 100644 --- a/application/src/main/java/org/thingsboard/server/controller/AiModelController.java +++ b/application/src/main/java/org/thingsboard/server/controller/AiModelController.java @@ -165,7 +165,7 @@ class AiModelController extends BaseController { @PostMapping("/chat") public DeferredResult sendChatRequest(@Valid @RequestBody TbChatRequest tbChatRequest) { ChatRequest langChainChatRequest = tbChatRequest.toLangChainChatRequest(); - AiChatModelConfig chatModelConfig = tbChatRequest.chatModelConfig(); + AiChatModelConfig chatModelConfig = tbChatRequest.chatModelConfig(); ListenableFuture future = aiChatModelService.sendChatRequestAsync(chatModelConfig, langChainChatRequest) .transform(chatResponse -> (TbChatResponse) new TbChatResponse.Success(chatResponse.aiMessage().text()), directExecutor()) diff --git a/application/src/main/java/org/thingsboard/server/controller/BaseController.java b/application/src/main/java/org/thingsboard/server/controller/BaseController.java index de69c239e9..2db9d90e6c 100644 --- a/application/src/main/java/org/thingsboard/server/controller/BaseController.java +++ b/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"; diff --git a/application/src/main/java/org/thingsboard/server/controller/CalculatedFieldController.java b/application/src/main/java/org/thingsboard/server/controller/CalculatedFieldController.java index bf42a5c044..ee796c37f8 100644 --- a/application/src/main/java/org/thingsboard/server/controller/CalculatedFieldController.java +++ b/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 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 getCalculatedFieldsByEntityId( + @GetMapping(value = "/calculatedField/{entityType}/{entityId}", params = {"pageSize", "page"}) + public PageData 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)", 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 212d363280..6c3aca6f67 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 @@ -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 > FluentFuture sendChatRequestAsync(AiChatModelConfig chatModelConfig, ChatRequest chatRequest) { + public , P extends AiProviderConfig> FluentFuture sendChatRequestAsync(AiChatModelConfig chatModelConfig, ChatRequest chatRequest) { ChatModel langChainChatModel = chatModelConfig.configure(chatModelConfigurer); if (langChainChatModel.provider() == ModelProvider.GITHUB_MODELS) { chatRequest = prepareGithubChatRequest(chatRequest); diff --git a/application/src/main/java/org/thingsboard/server/service/ai/Langchain4jChatModelConfigurerImpl.java b/application/src/main/java/org/thingsboard/server/service/ai/Langchain4jChatModelConfigurerImpl.java index 28d696468c..4ad975eb64 100644 --- a/application/src/main/java/org/thingsboard/server/service/ai/Langchain4jChatModelConfigurerImpl.java +++ b/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()); diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/ApiFeature.java b/common/data/src/main/java/org/thingsboard/server/common/data/ApiFeature.java index 335b9efd16..723ad829b6 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/ApiFeature.java +++ b/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"), diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/ai/dto/TbChatRequest.java b/common/data/src/main/java/org/thingsboard/server/common/data/ai/dto/TbChatRequest.java index c39a18ae6d..7a408ea0a9 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/ai/dto/TbChatRequest.java +++ b/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() { diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/ai/model/AiModelConfig.java b/common/data/src/main/java/org/thingsboard/server/common/data/ai/model/AiModelConfig.java index 18564e5665..52ed02fa46 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/ai/model/AiModelConfig.java +++ b/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 { @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(); diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/ai/model/chat/AiChatModelConfig.java b/common/data/src/main/java/org/thingsboard/server/common/data/ai/model/chat/AiChatModelConfig.java index 5f7772ed8b..920a055d3f 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/ai/model/chat/AiChatModelConfig.java +++ b/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> extends AiModelConfig +@Schema(description = "AI provider-specific configuration") +public sealed interface AiChatModelConfig, P extends AiProviderConfig> extends AiModelConfig

permits OpenAiChatModelConfig, AzureOpenAiChatModelConfig, GoogleAiGeminiChatModelConfig, GoogleVertexAiGeminiChatModelConfig, MistralAiChatModelConfig, AnthropicChatModelConfig, diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/ai/model/chat/AmazonBedrockChatModelConfig.java b/common/data/src/main/java/org/thingsboard/server/common/data/ai/model/chat/AmazonBedrockChatModelConfig.java index ee80230fee..8c0e9dd750 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/ai/model/chat/AmazonBedrockChatModelConfig.java +++ b/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 { +@Data +public final class AmazonBedrockChatModelConfig implements AiChatModelConfig { + + @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; } - } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/ai/model/chat/AnthropicChatModelConfig.java b/common/data/src/main/java/org/thingsboard/server/common/data/ai/model/chat/AnthropicChatModelConfig.java index 44b55c4c22..93b4272d56 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/ai/model/chat/AnthropicChatModelConfig.java +++ b/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 { +@Data +public final class AnthropicChatModelConfig implements AiChatModelConfig { + @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; diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/ai/model/chat/AzureOpenAiChatModelConfig.java b/common/data/src/main/java/org/thingsboard/server/common/data/ai/model/chat/AzureOpenAiChatModelConfig.java index 1e0d6d0c18..d6f46b7ae3 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/ai/model/chat/AzureOpenAiChatModelConfig.java +++ b/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 { +@Data +public final class AzureOpenAiChatModelConfig implements AiChatModelConfig { + + @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; diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/ai/model/chat/GitHubModelsChatModelConfig.java b/common/data/src/main/java/org/thingsboard/server/common/data/ai/model/chat/GitHubModelsChatModelConfig.java index 606f30599b..5c9aba001b 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/ai/model/chat/GitHubModelsChatModelConfig.java +++ b/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 { +@Data +public final class GitHubModelsChatModelConfig implements AiChatModelConfig { + + @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; diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/ai/model/chat/GoogleAiGeminiChatModelConfig.java b/common/data/src/main/java/org/thingsboard/server/common/data/ai/model/chat/GoogleAiGeminiChatModelConfig.java index 422c92ba97..8fa254a778 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/ai/model/chat/GoogleAiGeminiChatModelConfig.java +++ b/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 { +@Data +public final class GoogleAiGeminiChatModelConfig implements AiChatModelConfig { + @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; diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/ai/model/chat/GoogleVertexAiGeminiChatModelConfig.java b/common/data/src/main/java/org/thingsboard/server/common/data/ai/model/chat/GoogleVertexAiGeminiChatModelConfig.java index 3e298e52e2..8b5ab44e45 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/ai/model/chat/GoogleVertexAiGeminiChatModelConfig.java +++ b/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 { +@Data +public final class GoogleVertexAiGeminiChatModelConfig implements AiChatModelConfig { + + @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; diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/ai/model/chat/MistralAiChatModelConfig.java b/common/data/src/main/java/org/thingsboard/server/common/data/ai/model/chat/MistralAiChatModelConfig.java index 5713217fe9..77b4e77579 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/ai/model/chat/MistralAiChatModelConfig.java +++ b/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 { +@Data +public final class MistralAiChatModelConfig implements AiChatModelConfig { + + @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; diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/ai/model/chat/OllamaChatModelConfig.java b/common/data/src/main/java/org/thingsboard/server/common/data/ai/model/chat/OllamaChatModelConfig.java index 3f1856f630..ca3492e32c 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/ai/model/chat/OllamaChatModelConfig.java +++ b/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 { +@Data +public final class OllamaChatModelConfig implements AiChatModelConfig { + + @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; diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/ai/model/chat/OpenAiChatModelConfig.java b/common/data/src/main/java/org/thingsboard/server/common/data/ai/model/chat/OpenAiChatModelConfig.java index f74292cd76..6c6fafa0aa 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/ai/model/chat/OpenAiChatModelConfig.java +++ b/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 { +@Data +public final class OpenAiChatModelConfig implements AiChatModelConfig { + + @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; diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/ai/provider/AmazonBedrockProviderConfig.java b/common/data/src/main/java/org/thingsboard/server/common/data/ai/provider/AmazonBedrockProviderConfig.java index dc38440a66..2befbd92aa 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/ai/provider/AmazonBedrockProviderConfig.java +++ b/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, diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/alarm/AlarmComment.java b/common/data/src/main/java/org/thingsboard/server/common/data/alarm/AlarmComment.java index 92158057e7..f3950adff5 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/alarm/AlarmComment.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/alarm/AlarmComment.java @@ -47,7 +47,7 @@ public class AlarmComment extends BaseData 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 diff --git a/common/transport/http/src/main/java/org/thingsboard/server/transport/http/DeviceApiController.java b/common/transport/http/src/main/java/org/thingsboard/server/transport/http/DeviceApiController.java index 6595185a02..84195c8d7c 100644 --- a/common/transport/http/src/main/java/org/thingsboard/server/transport/http/DeviceApiController.java +++ b/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"; diff --git a/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/RuleEngineAiChatModelService.java b/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/RuleEngineAiChatModelService.java index 357b6c3340..c8e069ed74 100644 --- a/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/RuleEngineAiChatModelService.java +++ b/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 { - > FluentFuture sendChatRequestAsync(AiChatModelConfig chatModelConfig, ChatRequest chatRequest); + , P extends AiProviderConfig> FluentFuture sendChatRequestAsync(AiChatModelConfig chatModelConfig, ChatRequest chatRequest); } diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/ai/TbAiNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/ai/TbAiNode.java index bff72beb9b..07dcf3f52f 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/ai/TbAiNode.java +++ b/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 > FluentFuture sendChatRequestAsync(TbContext ctx, ChatRequest chatRequest) { + private , P extends AiProviderConfig> FluentFuture 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 chatModelConfig = (AiChatModelConfig) model.getConfiguration(); + AiChatModelConfig chatModelConfig = (AiChatModelConfig) model.getConfiguration(); chatModelConfig = chatModelConfig .withTimeoutSeconds(timeoutSeconds)