Skip to content

Commit b373618

Browse files
committed
feat: add langchain4j integration for llmprovider
1 parent c6e6446 commit b373618

File tree

7 files changed

+1702
-1
lines changed

7 files changed

+1702
-1
lines changed

pom.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@
9898
<jakarta.web.api.version>11.0.0</jakarta.web.api.version>
9999
<spring-data-commons.version>4.0.1</spring-data-commons.version>
100100
<reactor-core.version>3.8.2</reactor-core.version>
101+
<langchain4j.version>1.10.0</langchain4j.version>
101102

102103
<!-- spreadsheet -->
103104
<poi.version>5.5.1</poi.version>

vaadin-ai-components-flow-parent/vaadin-ai-components-flow/pom.xml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,12 @@
2727
<version>${project.version}</version>
2828
<scope>test</scope>
2929
</dependency>
30+
<dependency>
31+
<groupId>dev.langchain4j</groupId>
32+
<artifactId>langchain4j</artifactId>
33+
<version>${langchain4j.version}</version>
34+
<optional>true</optional>
35+
</dependency>
3036
<dependency>
3137
<groupId>io.projectreactor</groupId>
3238
<artifactId>reactor-core</artifactId>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
/*
2+
* Copyright 2000-2026 Vaadin Ltd.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
5+
* use this file except in compliance with the License. You may obtain a copy of
6+
* the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12+
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13+
* License for the specific language governing permissions and limitations under
14+
* the License.
15+
*/
16+
package com.vaadin.flow.component.ai.provider;
17+
18+
import java.nio.ByteBuffer;
19+
import java.nio.charset.CharacterCodingException;
20+
import java.nio.charset.CodingErrorAction;
21+
import java.nio.charset.StandardCharsets;
22+
import java.util.Base64;
23+
import java.util.Objects;
24+
25+
/**
26+
* Utility methods for LLM provider implementations.
27+
* <p>
28+
* Intended only for internal use and can be removed in the future.
29+
*/
30+
public final class LLMProviderHelpers {
31+
32+
/**
33+
* Supported content type categories for attachments.
34+
*/
35+
public enum AttachmentContentType {
36+
/** Image content types (image/*). */
37+
IMAGE,
38+
/** Text content types (text/*). */
39+
TEXT,
40+
/** PDF content types (application/pdf, application/x-pdf). */
41+
PDF,
42+
/** Unsupported or unknown content types. */
43+
UNSUPPORTED;
44+
45+
/**
46+
* Detects the content type category from a MIME type string.
47+
*
48+
* @param contentType
49+
* the MIME content type
50+
* @return the corresponding category, or {@code UNSUPPORTED} if not
51+
* recognized
52+
*/
53+
public static AttachmentContentType fromMimeType(String contentType) {
54+
if (contentType != null) {
55+
if (contentType.startsWith("image/")) {
56+
return IMAGE;
57+
}
58+
if (contentType.contains("text")) {
59+
return TEXT;
60+
}
61+
if (contentType.contains("pdf")) {
62+
return PDF;
63+
}
64+
}
65+
return UNSUPPORTED;
66+
}
67+
}
68+
69+
/**
70+
* Decodes byte array as UTF-8 text.
71+
*
72+
* @param data
73+
* the byte array to decode
74+
* @param fileName
75+
* the file name for error messages
76+
* @param strict
77+
* if {@code true}, throws exception on invalid UTF-8; if
78+
* {@code false}, replaces invalid sequences
79+
* @return the decoded string
80+
* @throws IllegalArgumentException
81+
* if {@code strict} is {@code true} and data contains invalid
82+
* UTF-8
83+
*/
84+
public static String decodeAsUtf8(byte[] data, String fileName,
85+
boolean strict) {
86+
if (!strict) {
87+
return new String(data, StandardCharsets.UTF_8);
88+
}
89+
var decoder = StandardCharsets.UTF_8.newDecoder()
90+
.onMalformedInput(CodingErrorAction.REPORT)
91+
.onUnmappableCharacter(CodingErrorAction.REPORT);
92+
try {
93+
return decoder.decode(ByteBuffer.wrap(data)).toString();
94+
} catch (CharacterCodingException e) {
95+
throw new IllegalArgumentException(
96+
"File '" + fileName + "' contains invalid UTF-8 data.", e);
97+
}
98+
}
99+
100+
/**
101+
* Converts binary data to a Base64-encoded data URL.
102+
*
103+
* @param data
104+
* the binary data to encode
105+
* @param contentType
106+
* the MIME content type (e.g., "image/png")
107+
* @return a data URL in the format "data:{contentType};base64,{data}"
108+
*/
109+
public static String toBase64DataUrl(byte[] data, String contentType) {
110+
var base64 = Base64.getEncoder().encodeToString(data);
111+
return "data:" + contentType + ";base64," + base64;
112+
}
113+
114+
/**
115+
* Formats text content as an attachment block.
116+
*
117+
* @param fileName
118+
* the file name to include in the attachment tag
119+
* @param content
120+
* the text content
121+
* @return formatted attachment string
122+
*/
123+
public static String formatTextAttachment(String fileName, String content) {
124+
return "\n<attachment filename=\"" + fileName + "\">\n" + content
125+
+ "\n</attachment>\n";
126+
}
127+
128+
/**
129+
* Validates that an attachment and its required fields are not
130+
* {@code null}.
131+
*
132+
* @param attachment
133+
* the attachment to validate
134+
* @throws NullPointerException
135+
* if attachment, content type, or data is {@code null}
136+
*/
137+
public static void validateAttachment(LLMProvider.Attachment attachment) {
138+
Objects.requireNonNull(attachment, "Attachment must not be null");
139+
Objects.requireNonNull(attachment.contentType(),
140+
"Attachment content type must not be null");
141+
Objects.requireNonNull(attachment.data(),
142+
"Attachment data must not be null");
143+
}
144+
}

0 commit comments

Comments
 (0)