/** * Author: Charuka Rathnayaka * Email: CharukaR@99x.io **/ export class Utility { /** * extractJsonFromLlmResponse * This function extracts the JSON object from the given LLM response. * @param input - The LLM response string * @returns The JSON object extracted from the LLM response * @throws Error if no valid JSON object found in the string **/ static extractJsonFromLlmResponse(input: string): { [key: string]: any } { try { // Check if the string contains '{' and '}' const hasCurlyBraces = input.includes('{') && input.includes('}'); // Check if the string contains '[' and ']' const hasSquareBraces = input.includes('[') && input.includes(']'); let jsonString = input; // If no curly braces but has square braces, replace the first '[' with '{' and last ']' with '}' if (!hasCurlyBraces && hasSquareBraces) { const firstSquareIndex = input.indexOf('['); const lastSquareIndex = input.lastIndexOf(']'); if (firstSquareIndex !== -1 && lastSquareIndex !== -1) { jsonString = input.substring(0, firstSquareIndex) + '{' + input.substring(firstSquareIndex + 1, lastSquareIndex) + '}' + input.substring(lastSquareIndex + 1); } } // Find the first '{' and the last '}' to extract the JSON object const firstBraceIndex = jsonString.indexOf('{'); const lastBraceIndex = jsonString.lastIndexOf('}'); if (firstBraceIndex !== -1 && lastBraceIndex !== -1) { // Extract the JSON substring const jsonSubString = jsonString.substring(firstBraceIndex, lastBraceIndex + 1); // Parse the JSON string return JSON.parse(jsonSubString); } else { throw new Error("No valid JSON object found in the string."); } } catch (error) { console.log("Error: Incorrect JSON Format;", error); return {}; } } /** * flattenJsonObject * This function flattens a JSON object. * @param obj - The JSON object to be flattened * @param parentKey - The parent key of the object * @param result - The result object * @returns The flattened JSON object **/ static flattenJsonObject(obj: { [key: string]: any }, parentKey: string = '', result: { [key: string]: any } = {}): { [key: string]: any } { for (const key in obj) { if (obj.hasOwnProperty(key)) { const value = obj[key]; const newKey = parentKey ? `${parentKey}_${key}` : key; if (typeof value === 'object' && value !== null && !Array.isArray(value)) { // Recursive call for nested objects Utility.flattenJsonObject(value, newKey, result); } else { // Assign the value to the flattened key result[newKey] = value; } } } return result; } static hasNestedObject(inputJson: Record): boolean { for (const key in inputJson) { if (inputJson.hasOwnProperty(key)) { const value = inputJson[key]; // Check if the value is an object and not null or an array if (typeof value === 'object' && value !== null && !Array.isArray(value)) { return true; // Nested object found } } } return false; // No nested objects } static convertNestedJsonToArrayOfSimpleJson(inputJson: Record): Record[] { const result: Record[] = []; const firstLevelKeys: Record = {}; // Iterate over each key in the input JSON object for (const key in inputJson) { if (inputJson.hasOwnProperty(key)) { const value = inputJson[key]; // Check if the value is a nested JSON object if (typeof value === 'object' && value !== null && !Array.isArray(value)) { const nestedObject: Record = { does_keys_aggregated: true }; // Flatten the nested object and prefix its keys for (const nestedKey in value) { if (value.hasOwnProperty(nestedKey)) { nestedObject[`${key}_${nestedKey}`] = value[nestedKey]; } } // Push each flattened nested object as a separate element in the result array result.push(nestedObject); } else { // Collect first-level keys and values firstLevelKeys[key] = value; } } } // If first-level keys are empty, push an empty object at the start result.unshift(Object.keys(firstLevelKeys).length > 0 ? firstLevelKeys : {}); return result; } static rebuildNestedJson(processedArray: Record[]): Record { var result: Record = {}; processedArray.forEach(item => { const doesKeysAggregated = item.does_keys_aggregated; delete item.does_keys_aggregated; // Iterate through each key-value pair in the current object if (!doesKeysAggregated) { result = { ...result, ...item }; } else { for (const key in item) { if (item.hasOwnProperty(key)) { const value = item[key]; // Check if the key contains an underscore if (key.includes('_')) { const splitted_array = key.split('_'); const outerKey = splitted_array[0]; const nestedKey = splitted_array.slice(1).join('_'); result[outerKey] = { ...result[outerKey], [nestedKey]: value }; } else { // Assign the key and value directly to the result object result[key] = value; } } } } }); return result; } static getClosestMatch(inputName: string, availableNames: string[]): string { return availableNames.reduce((closest, current) => Utility.getLevenshteinDistance(inputName, current) < Utility.getLevenshteinDistance(inputName, closest) ? current : closest ); } static getLevenshteinDistance(a: string, b: string): number { const stringA = a.toLowerCase(); const stringB = b.toLowerCase(); const matrix: number[][] = []; // Increment along the first column of each row for (let i = 0; i <= stringB.length; i++) { matrix[i] = [i]; } // Increment along the first row of each column for (let j = 0; j <= stringA.length; j++) { matrix[0][j] = j; } // Fill in the rest of the matrix for (let i = 1; i <= stringB.length; i++) { for (let j = 1; j <= stringA.length; j++) { if (stringB.charAt(i - 1) === stringA.charAt(j - 1)) { matrix[i][j] = matrix[i - 1][j - 1]; } else { matrix[i][j] = Math.min( matrix[i - 1][j - 1] + 1, // Substitution Math.min(matrix[i][j - 1] + 1, // Insertion matrix[i - 1][j] + 1) // Deletion ); } } } return matrix[stringB.length][stringA.length]; } }