@blank-utils/llm 0.5.2 → 0.5.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1022,6 +1022,31 @@ import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
1022
1022
  function cn(...inputs) {
1023
1023
  return twMerge(clsx(inputs));
1024
1024
  }
1025
+ async function resizeImageForWebLLM(dataUrl) {
1026
+ return new Promise((resolve, reject) => {
1027
+ const img = new Image();
1028
+ img.onload = () => {
1029
+ const TARGET_W = 1344;
1030
+ const TARGET_H = 1008;
1031
+ const canvas = document.createElement("canvas");
1032
+ canvas.width = TARGET_W;
1033
+ canvas.height = TARGET_H;
1034
+ const ctx = canvas.getContext("2d");
1035
+ if (!ctx) return resolve(dataUrl);
1036
+ ctx.fillStyle = "black";
1037
+ ctx.fillRect(0, 0, TARGET_W, TARGET_H);
1038
+ const scale = Math.min(TARGET_W / img.width, TARGET_H / img.height);
1039
+ const w = img.width * scale;
1040
+ const h = img.height * scale;
1041
+ const x = (TARGET_W - w) / 2;
1042
+ const y = (TARGET_H - h) / 2;
1043
+ ctx.drawImage(img, x, y, w, h);
1044
+ resolve(canvas.toDataURL("image/jpeg", 0.9));
1045
+ };
1046
+ img.onerror = () => resolve(dataUrl);
1047
+ img.src = dataUrl;
1048
+ });
1049
+ }
1025
1050
  function sanitizeMarkdownLanguageBlocks(markdown) {
1026
1051
  let cleanMarkdown = markdown;
1027
1052
  cleanMarkdown = cleanMarkdown.replace(/```([a-zA-Z0-9+#-]*)[_|█▋]+[ \t]*(?:\n|$)/gi, "```$1\n");
@@ -1213,21 +1238,27 @@ Additional instructions:
1213
1238
  ${systemPrompt}` : systemPrompt;
1214
1239
  apiMessages.push({ role: "system", content: finalSystemPrompt });
1215
1240
  }
1216
- currentMessages.forEach((m) => {
1241
+ for (const m of currentMessages) {
1217
1242
  let content = m.content;
1218
1243
  if (m.role === "user" && m.images && m.images.length > 0 && isVisionModel(modelId || "")) {
1244
+ const processedImages = await Promise.all(
1245
+ m.images.map((img) => resizeImageForWebLLM(img.dataUrl))
1246
+ );
1219
1247
  content = [
1220
1248
  { type: "text", text: m.content },
1221
- ...m.images.map((img) => ({ type: "image_url", image_url: { url: img.dataUrl } }))
1249
+ ...processedImages.map((url) => ({ type: "image_url", image_url: { url } }))
1222
1250
  ];
1223
1251
  }
1224
1252
  apiMessages.push({ role: m.role, content });
1225
- });
1253
+ }
1226
1254
  let finalUserContent = userContent;
1227
1255
  if (attachedImages.length > 0 && isVisionModel(modelId || "")) {
1256
+ const processedImages = await Promise.all(
1257
+ attachedImages.map((img) => resizeImageForWebLLM(img.dataUrl))
1258
+ );
1228
1259
  finalUserContent = [
1229
1260
  { type: "text", text: userContent },
1230
- ...attachedImages.map((img) => ({ type: "image_url", image_url: { url: img.dataUrl } }))
1261
+ ...processedImages.map((url) => ({ type: "image_url", image_url: { url } }))
1231
1262
  ];
1232
1263
  }
1233
1264
  apiMessages.push({ role: "user", content: finalUserContent });
package/dist/index.js CHANGED
@@ -22,7 +22,7 @@ import {
22
22
  useCompletion,
23
23
  useLLM,
24
24
  useStream
25
- } from "./chunk-QUWLNQIN.js";
25
+ } from "./chunk-6EZY4F42.js";
26
26
  export {
27
27
  Chat,
28
28
  ChatInput,
@@ -9,7 +9,7 @@ import {
9
9
  useCompletion,
10
10
  useLLM,
11
11
  useStream
12
- } from "../chunk-QUWLNQIN.js";
12
+ } from "../chunk-6EZY4F42.js";
13
13
  export {
14
14
  Chat,
15
15
  ChatApp,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@blank-utils/llm",
3
- "version": "0.5.2",
3
+ "version": "0.5.3",
4
4
  "description": "Run LLMs directly in your browser with WebGPU acceleration. Supports React hooks and eager background loading.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",