From 1711f6d8fc4be862d3d9636d6594483db4d70317 Mon Sep 17 00:00:00 2001 From: Marcus Schiesser <mail@marcusschiesser.de> Date: Tue, 3 Sep 2024 10:56:30 +0700 Subject: [PATCH] fix: Export imageToDataUrl for using images in chat (#1146) --- .changeset/tasty-hornets-repeat.md | 5 +++ examples/multimodal/chat.ts | 40 +++++++++++++++++++++++ packages/llamaindex/src/index.edge.ts | 1 + packages/llamaindex/src/internal/utils.ts | 6 +++- 4 files changed, 51 insertions(+), 1 deletion(-) create mode 100644 .changeset/tasty-hornets-repeat.md create mode 100644 examples/multimodal/chat.ts diff --git a/.changeset/tasty-hornets-repeat.md b/.changeset/tasty-hornets-repeat.md new file mode 100644 index 000000000..b4fd5ffb1 --- /dev/null +++ b/.changeset/tasty-hornets-repeat.md @@ -0,0 +1,5 @@ +--- +"llamaindex": patch +--- + +Export imageToDataUrl for using images in chat diff --git a/examples/multimodal/chat.ts b/examples/multimodal/chat.ts new file mode 100644 index 000000000..4884a11b5 --- /dev/null +++ b/examples/multimodal/chat.ts @@ -0,0 +1,40 @@ +// call pnpm tsx multimodal/load.ts first to init the storage +import { OpenAI, Settings, SimpleChatEngine, imageToDataUrl } from "llamaindex"; +import fs from "node:fs/promises"; + +import path from "path"; +// Update llm +Settings.llm = new OpenAI({ model: "gpt-4o-mini", maxTokens: 512 }); + +async function main() { + const chatEngine = new SimpleChatEngine(); + + // Load the image and convert it to a data URL + const imagePath = path.join(__dirname, ".", "data", "60.jpg"); + + // 1. you can read the buffer from the file + const imageBuffer = await fs.readFile(imagePath); + const dataUrl = await imageToDataUrl(imageBuffer); + // or 2. you can just pass the file path to the imageToDataUrl function + // const dataUrl = await imageToDataUrl(imagePath); + + // Update the image_url in the chat message + const response = await chatEngine.chat({ + message: [ + { + type: "text", + text: "What is in this image?", + }, + { + type: "image_url", + image_url: { + url: dataUrl, + }, + }, + ], + }); + + console.log(response.message.content); +} + +main().catch(console.error); diff --git a/packages/llamaindex/src/index.edge.ts b/packages/llamaindex/src/index.edge.ts index cf1162d73..100361ef2 100644 --- a/packages/llamaindex/src/index.edge.ts +++ b/packages/llamaindex/src/index.edge.ts @@ -37,6 +37,7 @@ export * from "./evaluation/index.js"; export * from "./extractors/index.js"; export * from "./indices/index.js"; export * from "./ingestion/index.js"; +export { imageToDataUrl } from "./internal/utils.js"; export * from "./llm/index.js"; export * from "./nodeParsers/index.js"; export * from "./objects/index.js"; diff --git a/packages/llamaindex/src/internal/utils.ts b/packages/llamaindex/src/internal/utils.ts index a301c2707..ab144a3cf 100644 --- a/packages/llamaindex/src/internal/utils.ts +++ b/packages/llamaindex/src/internal/utils.ts @@ -182,7 +182,9 @@ export function stringToImage(input: string): ImageType { } } -export async function imageToDataUrl(input: ImageType): Promise<string> { +export async function imageToDataUrl( + input: ImageType | Uint8Array, +): Promise<string> { // first ensure, that the input is a Blob if ( (input instanceof URL && input.protocol === "file:") || @@ -196,6 +198,8 @@ export async function imageToDataUrl(input: ImageType): Promise<string> { } else if (!(input instanceof Blob)) { if (input instanceof URL) { throw new Error(`Unsupported URL with protocol: ${input.protocol}`); + } else if (input instanceof Uint8Array) { + input = new Blob([input]); // convert Uint8Array to Blob } else { throw new Error(`Unsupported input type: ${typeof input}`); } -- GitLab