@llamaindex/core
Version:
LlamaIndex Core Module
290 lines (282 loc) • 8.99 kB
JavaScript
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;