UNPKG

@llamaindex/core

Version:
290 lines (282 loc) 8.99 kB
Object.defineProperty(exports, '__esModule', { value: true }); var env = require('@llamaindex/env'); var magicBytes_js = require('magic-bytes.js'); /** * Extracts just the text whether from * a multi-modal message * a single text message * or a query * * @param message The message to extract text from. * @returns The extracted text */ function extractText(message) { if (typeof message === "object" && "query" in message) { return extractText(message.query); } if (typeof message !== "string" && !Array.isArray(message)) { console.warn("extractText called with non-MessageContent message, this is likely a bug."); return `${message}`; } else if (typeof message !== "string" && Array.isArray(message)) { // message is of type MessageContentDetail[] - retrieve just the text parts and concatenate them // so we can pass them to the context generator return message.filter((c)=>c.type === "text").map((c)=>c.text).join("\n\n"); } else { return message; } } /** * Extracts a single text from a multi-modal message content * * @param message The message to extract images from. * @returns The extracted images */ function extractSingleText(message) { if (message.type === "text") { return message.text; } return null; } /** * Extracts an image from a multi-modal message content * * @param message The message to extract images from. * @returns The extracted images */ function extractImage(message) { if (message.type === "image_url") { return new URL(message.image_url.url); } return null; } const extractDataUrlComponents = (dataUrl)=>{ const parts = dataUrl.split(";base64,"); if (parts.length !== 2 || !parts[0].startsWith("data:")) { throw new Error("Invalid data URL"); } const mimeType = parts[0].slice(5); const base64 = parts[1]; return { mimeType, base64 }; }; function messagesToHistory(messages) { return messages.reduce((acc, message)=>{ acc += acc ? "\n" : ""; if (message.role === "user") { acc += `Human: ${message.content}`; } else { acc += `Assistant: ${message.content}`; } return acc; }, ""); } function toToolDescriptions(tools) { const toolsObj = tools.reduce((acc, tool)=>{ acc[tool.name] = tool.description; return acc; }, {}); return JSON.stringify(toolsObj, null, 4); } async function blobToDataUrl(input) { const buffer = Buffer.from(await input.arrayBuffer()); const mimes = magicBytes_js.filetypemime(buffer); if (mimes.length < 1) { throw new Error("Unsupported image type"); } return "data:" + mimes[0] + ";base64," + buffer.toString("base64"); } async function imageToDataUrl(input) { // first ensure, that the input is a Blob if (input instanceof URL && input.protocol === "file:" || typeof input === "string") { // string or file URL const dataBuffer = await env.fs.readFile(input instanceof URL ? input.pathname : input); input = new Blob([ dataBuffer ]); } 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}`); } } return await blobToDataUrl(input); } class BaseLLM { async complete(params) { const { prompt, stream, responseFormat } = params; if (stream) { const stream = await this.chat({ messages: [ { content: prompt, role: "user" } ], stream: true, ...responseFormat ? { responseFormat } : {} }); return streamConverter(stream, (chunk)=>{ return { raw: null, text: chunk.delta }; }); } const chatResponse = await this.chat({ messages: [ { content: prompt, role: "user" } ], ...responseFormat ? { responseFormat } : {} }); return { text: extractText(chatResponse.message.content), raw: chatResponse.raw }; } } class ToolCallLLM extends BaseLLM { } // TODO: move to a test package class MockLLM extends ToolCallLLM { constructor(options){ super(), this.supportToolCall = false; this.options = { timeBetweenToken: options?.timeBetweenToken ?? 20, responseMessage: options?.responseMessage ?? "This is a mock response" }; this.metadata = options?.metadata ?? { model: "MockLLM", temperature: 0.5, topP: 0.5, contextWindow: 1024, tokenizer: undefined, structuredOutput: false }; } async chat(params) { const responseMessage = this.options.responseMessage; const timeBetweenToken = this.options.timeBetweenToken; if (params.stream) { return async function*() { for (const char of responseMessage){ yield { delta: char, raw: {} }; await new Promise((resolve)=>setTimeout(resolve, timeBetweenToken)); } }(); } return { message: { content: responseMessage, role: "assistant" }, raw: {} }; } async complete(params) { const responseMessage = this.options.responseMessage; const timeBetweenToken = this.options.timeBetweenToken; if (params.stream) { return async function*() { for (const char of responseMessage){ yield { delta: char, text: char, raw: {} }; await new Promise((resolve)=>setTimeout(resolve, timeBetweenToken)); } }(); } return { text: responseMessage, raw: {} }; } } // eslint-disable-next-line @typescript-eslint/no-explicit-any /** * Type safe version of `Object.entries` */ // eslint-disable-next-line @typescript-eslint/no-explicit-any function objectEntries(obj) { return Object.entries(obj); } const isPromise = (obj)=>{ return obj != null && typeof obj === "object" && "then" in obj; }; const isAsyncIterable = (obj)=>{ return obj != null && typeof obj === "object" && Symbol.asyncIterator in obj; }; const isIterable = (obj)=>{ return obj != null && typeof obj === "object" && Symbol.iterator in obj; }; async function* streamConverter(stream, converter) { for await (const data of stream){ const newData = converter(data); if (newData === null) { return; } yield newData; } } async function* streamCallbacks(stream, callbacks) { let value; for await (value of stream){ yield value; } if (callbacks.finished) { callbacks.finished(value); } } async function* streamReducer(params) { let value = params.initialValue; for await (const data of params.stream){ value = params.reducer(value, data); yield data; } if (params.finished) { params.finished(value); } } /** * Prettify an error for AI to read */ function prettifyError(error) { if (error instanceof Error) { return `Error(${error.name}): ${error.message}`; } else { return `${error}`; } } function stringifyJSONToMessageContent(value) { return JSON.stringify(value, null, 2).replace(/"([^"]*)"/g, "$1"); } exports.MockLLM = MockLLM; exports.extractDataUrlComponents = extractDataUrlComponents; exports.extractImage = extractImage; exports.extractSingleText = extractSingleText; exports.extractText = extractText; exports.imageToDataUrl = imageToDataUrl; exports.isAsyncIterable = isAsyncIterable; exports.isIterable = isIterable; exports.isPromise = isPromise; exports.messagesToHistory = messagesToHistory; exports.objectEntries = objectEntries; exports.prettifyError = prettifyError; exports.streamCallbacks = streamCallbacks; exports.streamConverter = streamConverter; exports.streamReducer = streamReducer; exports.stringifyJSONToMessageContent = stringifyJSONToMessageContent; exports.toToolDescriptions = toToolDescriptions;