+
ai-models.baseurl
@@ -264,15 +264,18 @@
-
- warning
-
+ type="number" step="1" placeholder="{{ 'ai-models.set' | translate }}">
+
+
+ }
+ @if (modelFieldsList.includes('contextLength')) {
+
}
diff --git a/ui-ngx/src/app/modules/home/components/ai-model/ai-model-dialog.component.ts b/ui-ngx/src/app/modules/home/components/ai-model/ai-model-dialog.component.ts
index e6490cd84d..3294c6ac76 100644
--- a/ui-ngx/src/app/modules/home/components/ai-model/ai-model-dialog.component.ts
+++ b/ui-ngx/src/app/modules/home/components/ai-model/ai-model-dialog.component.ts
@@ -108,7 +108,8 @@ export class AIModelDialogComponent extends DialogComponent, 'label'>, HasTenantId
frequencyPenalty?: number;
presencePenalty?: number;
maxOutputTokens?: number;
+ contextLength?: number;
}
}
@@ -91,7 +92,7 @@ export const ProviderFieldsAllList = [
'baseUrl'
];
-export const ModelFieldsAllList = ['temperature', 'topP', 'topK', 'frequencyPenalty', 'presencePenalty', 'maxOutputTokens'];
+export const ModelFieldsAllList = ['temperature', 'topP', 'topK', 'frequencyPenalty', 'presencePenalty', 'maxOutputTokens', 'contextLength'];
export const AiModelMap = new Map([
[
@@ -200,7 +201,7 @@ export const AiModelMap = new Map
Date: Mon, 22 Sep 2025 12:18:06 +0300
Subject: [PATCH 09/11] AI models: add auth support for Ollama
---
.../Langchain4jChatModelConfigurerImpl.java | 28 +++++++++++++---
.../ai/provider/OllamaProviderConfig.java | 32 +++++++++++++++++--
2 files changed, 53 insertions(+), 7 deletions(-)
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 84b09b9188..2cb6c2097f 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
@@ -35,6 +35,7 @@ import dev.langchain4j.model.mistralai.MistralAiChatModel;
import dev.langchain4j.model.ollama.OllamaChatModel;
import dev.langchain4j.model.openai.OpenAiChatModel;
import dev.langchain4j.model.vertexai.gemini.VertexAiGeminiChatModel;
+import org.springframework.http.HttpHeaders;
import org.springframework.stereotype.Component;
import org.thingsboard.server.common.data.ai.model.chat.AmazonBedrockChatModelConfig;
import org.thingsboard.server.common.data.ai.model.chat.AnthropicChatModelConfig;
@@ -49,6 +50,7 @@ import org.thingsboard.server.common.data.ai.model.chat.OpenAiChatModelConfig;
import org.thingsboard.server.common.data.ai.provider.AmazonBedrockProviderConfig;
import org.thingsboard.server.common.data.ai.provider.AzureOpenAiProviderConfig;
import org.thingsboard.server.common.data.ai.provider.GoogleVertexAiGeminiProviderConfig;
+import org.thingsboard.server.common.data.ai.provider.OllamaProviderConfig;
import software.amazon.awssdk.auth.credentials.AwsBasicCredentials;
import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider;
import software.amazon.awssdk.regions.Region;
@@ -56,7 +58,11 @@ import software.amazon.awssdk.services.bedrockruntime.BedrockRuntimeClient;
import java.io.ByteArrayInputStream;
import java.io.IOException;
+import java.nio.charset.StandardCharsets;
import java.time.Duration;
+import java.util.Base64;
+
+import static java.util.Collections.singletonMap;
@Component
class Langchain4jChatModelConfigurerImpl implements Langchain4jChatModelConfigurer {
@@ -136,7 +142,7 @@ class Langchain4jChatModelConfigurerImpl implements Langchain4jChatModelConfigur
// set request timeout from model config
if (chatModelConfig.timeoutSeconds() != null) {
- retrySettings.setTotalTimeout(org.threeten.bp.Duration.ofSeconds(chatModelConfig.timeoutSeconds()));
+ retrySettings.setTotalTimeoutDuration(Duration.ofSeconds(chatModelConfig.timeoutSeconds()));
}
// set updated retry settings
@@ -266,7 +272,7 @@ class Langchain4jChatModelConfigurerImpl implements Langchain4jChatModelConfigur
@Override
public ChatModel configureChatModel(OllamaChatModelConfig chatModelConfig) {
- return OllamaChatModel.builder()
+ var builder = OllamaChatModel.builder()
.baseUrl(chatModelConfig.providerConfig().baseUrl())
.modelName(chatModelConfig.modelId())
.temperature(chatModelConfig.temperature())
@@ -275,8 +281,22 @@ class Langchain4jChatModelConfigurerImpl implements Langchain4jChatModelConfigur
.numCtx(chatModelConfig.contextLength())
.numPredict(chatModelConfig.maxOutputTokens())
.timeout(toDuration(chatModelConfig.timeoutSeconds()))
- .maxRetries(chatModelConfig.maxRetries())
- .build();
+ .maxRetries(chatModelConfig.maxRetries());
+
+ var auth = chatModelConfig.providerConfig().auth();
+ if (auth instanceof OllamaProviderConfig.OllamaAuth.Basic basicAuth) {
+ String credentials = basicAuth.username() + ":" + basicAuth.password();
+ String encodedCredentials = Base64.getEncoder().encodeToString(credentials.getBytes(StandardCharsets.UTF_8));
+ builder.customHeaders(singletonMap(HttpHeaders.AUTHORIZATION, "Basic " + encodedCredentials));
+ } else if (auth instanceof OllamaProviderConfig.OllamaAuth.Token tokenAuth) {
+ builder.customHeaders(singletonMap(HttpHeaders.AUTHORIZATION, "Bearer " + tokenAuth.token()));
+ } else if (auth instanceof OllamaProviderConfig.OllamaAuth.None) {
+ // do nothing
+ } else {
+ throw new UnsupportedOperationException("Unknown authentication type: " + auth.getClass().getSimpleName());
+ }
+
+ return builder.build();
}
private static Duration toDuration(Integer timeoutSeconds) {
diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/ai/provider/OllamaProviderConfig.java b/common/data/src/main/java/org/thingsboard/server/common/data/ai/provider/OllamaProviderConfig.java
index fc0a2d6fd8..39bb57834c 100644
--- a/common/data/src/main/java/org/thingsboard/server/common/data/ai/provider/OllamaProviderConfig.java
+++ b/common/data/src/main/java/org/thingsboard/server/common/data/ai/provider/OllamaProviderConfig.java
@@ -15,8 +15,34 @@
*/
package org.thingsboard.server.common.data.ai.provider;
-import jakarta.validation.constraints.NotBlank;
+import com.fasterxml.jackson.annotation.JsonSubTypes;
+import com.fasterxml.jackson.annotation.JsonTypeInfo;
+import jakarta.validation.Valid;
+import jakarta.validation.constraints.NotNull;
public record OllamaProviderConfig(
- @NotBlank String baseUrl
-) implements AiProviderConfig {}
+ @NotNull String baseUrl,
+ @NotNull @Valid OllamaAuth auth
+) implements AiProviderConfig {
+
+ @JsonTypeInfo(
+ use = JsonTypeInfo.Id.NAME,
+ include = JsonTypeInfo.As.PROPERTY,
+ property = "type"
+ )
+ @JsonSubTypes({
+ @JsonSubTypes.Type(value = OllamaAuth.None.class, name = "NONE"),
+ @JsonSubTypes.Type(value = OllamaAuth.Basic.class, name = "BASIC"),
+ @JsonSubTypes.Type(value = OllamaAuth.Token.class, name = "TOKEN")
+ })
+ public sealed interface OllamaAuth {
+
+ record None() implements OllamaAuth {}
+
+ record Basic(@NotNull String username, @NotNull String password) implements OllamaAuth {}
+
+ record Token(@NotNull String token) implements OllamaAuth {}
+
+ }
+
+}
From 8a6015f04e7b2b4471f9d801517c9e40da6ef0d3 Mon Sep 17 00:00:00 2001
From: ArtemDzhereleiko
Date: Thu, 25 Sep 2025 15:44:50 +0300
Subject: [PATCH 10/11] UI: Add authentication for Ollama model
---
.../ai-model/ai-model-dialog.component.html | 87 +++++++++++++++----
.../ai-model/ai-model-dialog.component.ts | 67 +++++++++++---
.../src/app/shared/models/ai-model.models.ts | 11 +++
.../assets/locale/locale.constant-en_US.json | 16 +++-
4 files changed, 153 insertions(+), 28 deletions(-)
diff --git a/ui-ngx/src/app/modules/home/components/ai-model/ai-model-dialog.component.html b/ui-ngx/src/app/modules/home/components/ai-model/ai-model-dialog.component.html
index c730850474..abfe8500b4 100644
--- a/ui-ngx/src/app/modules/home/components/ai-model/ai-model-dialog.component.html
+++ b/ui-ngx/src/app/modules/home/components/ai-model/ai-model-dialog.component.html
@@ -55,31 +55,34 @@
-
-
- {{ 'legend.show-total' | translate }}
-
+
+
+ {{ 'legend.show-total' | translate }}
+
+
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/chart/bar-chart-widget.models.ts b/ui-ngx/src/app/modules/home/components/widget/lib/chart/bar-chart-widget.models.ts
index 036ba70c04..3f76eb18cf 100644
--- a/ui-ngx/src/app/modules/home/components/widget/lib/chart/bar-chart-widget.models.ts
+++ b/ui-ngx/src/app/modules/home/components/widget/lib/chart/bar-chart-widget.models.ts
@@ -68,6 +68,7 @@ export const barChartWidgetBarsChartSettings = (settings: BarChartWidgetSettings
showTotal: false,
animation: settings.animation,
showLegend: settings.showLegend,
+ legendShowTotal: settings.legendShowTotal,
showTooltip: settings.showTooltip,
tooltipValueType: settings.tooltipValueType,
tooltipValueDecimals: settings.tooltipValueDecimals,
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/chart/doughnut-widget.models.ts b/ui-ngx/src/app/modules/home/components/widget/lib/chart/doughnut-widget.models.ts
index 0d8c1ba9fa..0ef277ea8b 100644
--- a/ui-ngx/src/app/modules/home/components/widget/lib/chart/doughnut-widget.models.ts
+++ b/ui-ngx/src/app/modules/home/components/widget/lib/chart/doughnut-widget.models.ts
@@ -88,6 +88,7 @@ export const doughnutPieChartSettings = (settings: DoughnutWidgetSettings): Deep
showTotal: settings.layout === DoughnutLayout.with_total,
animation: settings.animation,
showLegend: settings.showLegend,
+ legendShowTotal: settings.legendShowTotal,
totalValueFont: settings.totalValueFont,
totalValueColor: settings.totalValueColor,
showLabel: false,
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/chart/latest-chart.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/chart/latest-chart.component.ts
index 80be75d98d..85905dfd3e 100644
--- a/ui-ngx/src/app/modules/home/components/widget/lib/chart/latest-chart.component.ts
+++ b/ui-ngx/src/app/modules/home/components/widget/lib/chart/latest-chart.component.ts
@@ -82,8 +82,7 @@ export class LatestChartComponent implements OnInit, OnDestroy, AfterViewInit {
padding: string;
get legendItems(): LatestChartLegendItem[] {
- let items = this.latestChart ? this.latestChart.getLegendItems() : [];
- return this.legendShowTotal ? items : items.filter(item => !item.total);
+ return this.latestChart ? this.latestChart.getLegendItems() : [];
}
legendLabelStyle: ComponentStyle;
@@ -93,7 +92,6 @@ export class LatestChartComponent implements OnInit, OnDestroy, AfterViewInit {
private shapeResize$: ResizeObserver;
private legendHorizontal: boolean;
- private legendShowTotal: boolean;
private latestChart: TbLatestChart;
@@ -121,7 +119,6 @@ export class LatestChartComponent implements OnInit, OnDestroy, AfterViewInit {
this.legendValueStyle = textStyle(this.settings.legendValueFont);
this.disabledLegendValueStyle = textStyle(this.settings.legendValueFont);
this.legendValueStyle.color = this.settings.legendValueColor;
- this.legendShowTotal = this.settings.legendShowTotal;
}
}
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/chart/latest-chart.models.ts b/ui-ngx/src/app/modules/home/components/widget/lib/chart/latest-chart.models.ts
index 639938bad6..aa1ac43644 100644
--- a/ui-ngx/src/app/modules/home/components/widget/lib/chart/latest-chart.models.ts
+++ b/ui-ngx/src/app/modules/home/components/widget/lib/chart/latest-chart.models.ts
@@ -87,6 +87,7 @@ export interface LatestChartSettings extends LatestChartTooltipSettings {
sortSeries: boolean;
showTotal?: boolean;
showLegend: boolean;
+ legendShowTotal: boolean;
animation: ChartAnimationSettings;
}
@@ -96,6 +97,7 @@ export const latestChartDefaultSettings: LatestChartSettings = {
sortSeries: false,
showTotal: false,
showLegend: true,
+ legendShowTotal: true,
animation: mergeDeep({} as ChartAnimationSettings, chartAnimationDefaultSettings)
};
@@ -105,14 +107,12 @@ export interface LatestChartWidgetSettings extends LatestChartSettings {
legendLabelColor: string;
legendValueFont: Font;
legendValueColor: string;
- legendShowTotal: boolean;
background: BackgroundSettings;
padding: string;
}
export const latestChartWidgetDefaultSettings: LatestChartWidgetSettings = {
...latestChartDefaultSettings,
- showLegend: true,
legendPosition: LegendPosition.bottom,
legendLabelFont: {
family: 'Roboto',
@@ -132,7 +132,6 @@ export const latestChartWidgetDefaultSettings: LatestChartWidgetSettings = {
lineHeight: '20px'
},
legendValueColor: 'rgba(0, 0, 0, 0.87)',
- legendShowTotal: true,
background: {
type: BackgroundType.color,
color: '#fff',
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/chart/latest-chart.ts b/ui-ngx/src/app/modules/home/components/widget/lib/chart/latest-chart.ts
index b9f0940b52..9e525cd794 100644
--- a/ui-ngx/src/app/modules/home/components/widget/lib/chart/latest-chart.ts
+++ b/ui-ngx/src/app/modules/home/components/widget/lib/chart/latest-chart.ts
@@ -36,6 +36,7 @@ import { ValueFormatProcessor } from '@shared/models/widget-settings.models';
export abstract class TbLatestChart {
private readonly shapeResize$: ResizeObserver;
+ private showTotalValueInLegend: boolean;
protected readonly settings: S;
@@ -121,7 +122,8 @@ export abstract class TbLatestChart {
this.legendItems.sort((a, b) => a.label.localeCompare(b.label));
}
}
- if (this.settings.showLegend && !this.settings.showTotal) {
+ this.showTotalValueInLegend = this.settings.showLegend && !this.settings.showTotal && this.settings.legendShowTotal;
+ if (this.showTotalValueInLegend) {
this.legendItems.push(
{
value: '--',
@@ -252,11 +254,11 @@ export abstract class TbLatestChart {
if (this.settings.showTotal || this.settings.showLegend) {
if (hasValue) {
this.totalText = this.valueFormatter.format(this.total);
- if (this.settings.showLegend && !this.settings.showTotal) {
+ if (this.showTotalValueInLegend) {
this.legendItems[this.legendItems.length - 1].hasValue = true;
this.legendItems[this.legendItems.length - 1].value = this.totalText;
}
- } else if (this.settings.showLegend && !this.settings.showTotal) {
+ } else if (this.showTotalValueInLegend) {
this.legendItems[this.legendItems.length - 1].hasValue = false;
this.legendItems[this.legendItems.length - 1].value = '--';
}
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/chart/pie-chart-widget.models.ts b/ui-ngx/src/app/modules/home/components/widget/lib/chart/pie-chart-widget.models.ts
index a98cdfdd4a..cddf75b9f9 100644
--- a/ui-ngx/src/app/modules/home/components/widget/lib/chart/pie-chart-widget.models.ts
+++ b/ui-ngx/src/app/modules/home/components/widget/lib/chart/pie-chart-widget.models.ts
@@ -64,6 +64,7 @@ export const pieChartWidgetPieChartSettings = (settings: PieChartWidgetSettings)
showTotal: false,
animation: settings.animation,
showLegend: settings.showLegend,
+ legendShowTotal: settings.legendShowTotal,
showLabel: settings.showLabel,
labelPosition: settings.labelPosition,
labelFont: settings.labelFont,
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/chart/polar-area-widget.models.ts b/ui-ngx/src/app/modules/home/components/widget/lib/chart/polar-area-widget.models.ts
index 70b4520159..4b744ce9c3 100644
--- a/ui-ngx/src/app/modules/home/components/widget/lib/chart/polar-area-widget.models.ts
+++ b/ui-ngx/src/app/modules/home/components/widget/lib/chart/polar-area-widget.models.ts
@@ -72,6 +72,7 @@ export const polarAreaChartWidgetBarsChartSettings = (settings: PolarAreaChartWi
showTotal: false,
animation: settings.animation,
showLegend: settings.showLegend,
+ legendShowTotal: settings.legendShowTotal,
showTooltip: settings.showTooltip,
tooltipValueType: settings.tooltipValueType,
tooltipValueDecimals: settings.tooltipValueDecimals,
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/chart/radar-chart-widget.models.ts b/ui-ngx/src/app/modules/home/components/widget/lib/chart/radar-chart-widget.models.ts
index ec42955b4d..b3be129489 100644
--- a/ui-ngx/src/app/modules/home/components/widget/lib/chart/radar-chart-widget.models.ts
+++ b/ui-ngx/src/app/modules/home/components/widget/lib/chart/radar-chart-widget.models.ts
@@ -135,6 +135,7 @@ export const radarChartWidgetRadarChartSettings = (settings: RadarChartWidgetSet
showTotal: false,
animation: settings.animation,
showLegend: settings.showLegend,
+ legendShowTotal: settings.legendShowTotal,
showTooltip: settings.showTooltip,
tooltipValueType: settings.tooltipValueType,
tooltipValueDecimals: settings.tooltipValueDecimals,
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/latest-chart-widget-settings.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/latest-chart-widget-settings.component.html
index fe071f16a0..66d0234914 100644
--- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/latest-chart-widget-settings.component.html
+++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/latest-chart-widget-settings.component.html
@@ -61,9 +61,11 @@
-
- {{ 'legend.show-total' | translate }}
-
+
+
+ {{ 'legend.show-total' | translate }}
+
+