Skip to content

Commit 4f2eecc

Browse files
authored
feat(tool): Support multimodal tool (#241)
1 parent 6dd1808 commit 4f2eecc

14 files changed

Lines changed: 4040 additions & 6 deletions

File tree

agentscope-core/src/main/java/io/agentscope/core/formatter/MediaUtils.java

Lines changed: 90 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,20 @@
1616
package io.agentscope.core.formatter;
1717

1818
import com.openai.models.chat.completions.ChatCompletionContentPartInputAudio;
19+
import java.awt.Graphics2D;
20+
import java.awt.image.BufferedImage;
21+
import java.io.ByteArrayInputStream;
22+
import java.io.ByteArrayOutputStream;
1923
import java.io.IOException;
2024
import java.io.InputStream;
2125
import java.net.HttpURLConnection;
26+
import java.net.URI;
2227
import java.net.URL;
2328
import java.nio.file.Files;
2429
import java.nio.file.Path;
2530
import java.util.Base64;
2631
import java.util.List;
32+
import javax.imageio.ImageIO;
2733
import org.slf4j.Logger;
2834
import org.slf4j.LoggerFactory;
2935

@@ -128,6 +134,21 @@ public static String downloadUrlToBase64(String url) throws IOException {
128134
}
129135
}
130136

137+
/**
138+
* Convert a URL to a file:// protocol URL or leave as-is for web URLs.
139+
*
140+
* @param url URL or file path
141+
* @return file:// protocol URL or original URL (e.g., file:///absolute/path/image.png)
142+
* @throws IOException If the file does not exist
143+
*/
144+
public static String urlToProtocolUrl(String url) throws IOException {
145+
if (isFileExists(url)) {
146+
return toFileProtocolUrl(url);
147+
}
148+
149+
return url;
150+
}
151+
131152
/**
132153
* Convert a local file path to file:// protocol URL.
133154
* Resolves relative paths to absolute and validates file existence.
@@ -146,12 +167,66 @@ public static String toFileProtocolUrl(String path) throws IOException {
146167
}
147168

148169
/**
149-
* Convert a file to a data URL with base64 encoding.
150-
* Format: data:{mediaType};base64,{base64Data}
170+
* Convert a file or web URL to an InputStream.
171+
*
172+
* @param url The file or web URL
173+
* @return An InputStream for the resource
174+
* @throws IOException If the resource read failed
175+
*/
176+
public static InputStream urlToInputStream(String url) throws IOException {
177+
Path path = Path.of(url);
178+
if (Files.exists(path)) {
179+
// Treat as local file
180+
return Files.newInputStream(path);
181+
} else {
182+
// Treat as web URL
183+
return URI.create(url).toURL().openStream();
184+
}
185+
}
186+
187+
/**
188+
* Convert a file or web URL to an InputStream with RGBA image.
189+
* @param url a local file path or web URL
190+
* @return an InputStream with RGBA image
191+
* @throws IOException if the resource convert failed
192+
* @throws IllegalArgumentException if the resource read failed
151193
*/
152-
public static String urlToBase64DataUrl(String path) throws IOException {
153-
String base64 = fileToBase64(path);
154-
String mediaType = determineMediaType(path);
194+
public static InputStream urlToRgbaImageInputStream(String url) throws IOException {
195+
BufferedImage img = ImageIO.read(urlToInputStream(url));
196+
if (img == null) {
197+
throw new IllegalArgumentException("Unable to read image from: " + url);
198+
}
199+
200+
// Ensure image has alpha channel (RGBA)
201+
BufferedImage rgbaImg =
202+
new BufferedImage(img.getWidth(), img.getHeight(), BufferedImage.TYPE_INT_ARGB);
203+
Graphics2D graphics = rgbaImg.createGraphics();
204+
try {
205+
graphics.drawImage(img, 0, 0, null);
206+
ByteArrayOutputStream bos = new ByteArrayOutputStream();
207+
ImageIO.write(rgbaImg, "png", bos);
208+
return new ByteArrayInputStream(bos.toByteArray());
209+
} finally {
210+
graphics.dispose();
211+
}
212+
}
213+
214+
/**
215+
* Convert a file or web URL to a data URL with base64 encoding.
216+
* @param url a local file path or web url
217+
* @return a data URL with base64 encoding, the format is data:{mediaType};base64,{base64Data}
218+
*/
219+
public static String urlToBase64DataUrl(String url) throws IOException {
220+
String base64;
221+
if (isFileExists(url)) {
222+
// Treat as local file
223+
base64 = fileToBase64(url);
224+
} else {
225+
// Treat as web URL
226+
base64 = downloadUrlToBase64(url);
227+
}
228+
229+
String mediaType = determineMediaType(url);
155230
return String.format("data:%s;base64,%s", mediaType, base64);
156231
}
157232

@@ -254,7 +329,7 @@ public static ChatCompletionContentPartInputAudio.InputAudio.Format determineAud
254329
/**
255330
* Extract file extension from path or URL.
256331
*/
257-
private static String getExtension(String path) {
332+
public static String getExtension(String path) {
258333
if (path == null) {
259334
return "";
260335
}
@@ -267,6 +342,15 @@ private static String getExtension(String path) {
267342
return "";
268343
}
269344

345+
/**
346+
* Check if a file exists.
347+
* @param path a local file path
348+
* @return true: exists, false: not exists
349+
*/
350+
public static boolean isFileExists(String path) {
351+
return Files.exists(Path.of(path));
352+
}
353+
270354
/**
271355
* Check file size before reading.
272356
*/

0 commit comments

Comments
 (0)