| import axios from 'axios' |
| import { load } from 'cheerio' |
| import * as fs from 'fs' |
| import * as path from 'path' |
| import { BaseCallbackHandler } from 'langchain/callbacks' |
| import { Server } from 'socket.io' |
| import { ChainValues } from 'langchain/dist/schema' |
|
|
| export const numberOrExpressionRegex = '^(\\d+\\.?\\d*|{{.*}})$' |
| export const notEmptyRegex = '(.|\\s)*\\S(.|\\s)*' |
|
|
| |
| |
| |
| |
| |
| |
| |
| export const getBaseClasses = (targetClass: any) => { |
| const baseClasses: string[] = [] |
|
|
| if (targetClass instanceof Function) { |
| let baseClass = targetClass |
|
|
| while (baseClass) { |
| const newBaseClass = Object.getPrototypeOf(baseClass) |
| if (newBaseClass && newBaseClass !== Object && newBaseClass.name) { |
| baseClass = newBaseClass |
| baseClasses.push(baseClass.name) |
| } else { |
| break |
| } |
| } |
| } |
| return baseClasses |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| export function serializeQueryParams(params: any, skipIndex?: boolean): string { |
| const parts: any[] = [] |
|
|
| const encode = (val: string) => { |
| return encodeURIComponent(val) |
| .replace(/%3A/gi, ':') |
| .replace(/%24/g, '$') |
| .replace(/%2C/gi, ',') |
| .replace(/%20/g, '+') |
| .replace(/%5B/gi, '[') |
| .replace(/%5D/gi, ']') |
| } |
|
|
| const convertPart = (key: string, val: any) => { |
| if (val instanceof Date) val = val.toISOString() |
| else if (val instanceof Object) val = JSON.stringify(val) |
|
|
| parts.push(encode(key) + '=' + encode(val)) |
| } |
|
|
| Object.entries(params).forEach(([key, val]) => { |
| if (val === null || typeof val === 'undefined') return |
|
|
| if (Array.isArray(val)) val.forEach((v, i) => convertPart(`${key}${skipIndex ? '' : `[${i}]`}`, v)) |
| else convertPart(key, val) |
| }) |
|
|
| return parts.join('&') |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| export function handleErrorMessage(error: any): string { |
| let errorMessage = '' |
|
|
| if (error.message) { |
| errorMessage += error.message + '. ' |
| } |
|
|
| if (error.response && error.response.data) { |
| if (error.response.data.error) { |
| if (typeof error.response.data.error === 'object') errorMessage += JSON.stringify(error.response.data.error) + '. ' |
| else if (typeof error.response.data.error === 'string') errorMessage += error.response.data.error + '. ' |
| } else if (error.response.data.msg) errorMessage += error.response.data.msg + '. ' |
| else if (error.response.data.Message) errorMessage += error.response.data.Message + '. ' |
| else if (typeof error.response.data === 'string') errorMessage += error.response.data + '. ' |
| } |
|
|
| if (!errorMessage) errorMessage = 'Unexpected Error.' |
|
|
| return errorMessage |
| } |
|
|
| |
| |
| |
| |
| |
| export const getNodeModulesPackagePath = (packageName: string): string => { |
| const checkPaths = [ |
| path.join(__dirname, '..', 'node_modules', packageName), |
| path.join(__dirname, '..', '..', 'node_modules', packageName), |
| path.join(__dirname, '..', '..', '..', 'node_modules', packageName), |
| path.join(__dirname, '..', '..', '..', '..', 'node_modules', packageName), |
| path.join(__dirname, '..', '..', '..', '..', '..', 'node_modules', packageName) |
| ] |
| for (const checkPath of checkPaths) { |
| if (fs.existsSync(checkPath)) { |
| return checkPath |
| } |
| } |
| return '' |
| } |
|
|
| |
| |
| |
| |
| |
| export const getInputVariables = (paramValue: string): string[] => { |
| let returnVal = paramValue |
| const variableStack = [] |
| const inputVariables = [] |
| let startIdx = 0 |
| const endIdx = returnVal.length |
|
|
| while (startIdx < endIdx) { |
| const substr = returnVal.substring(startIdx, startIdx + 1) |
|
|
| |
| if (substr === '{') { |
| variableStack.push({ substr, startIdx: startIdx + 1 }) |
| } |
|
|
| |
| if (substr === '}' && variableStack.length > 0 && variableStack[variableStack.length - 1].substr === '{') { |
| const variableStartIdx = variableStack[variableStack.length - 1].startIdx |
| const variableEndIdx = startIdx |
| const variableFullPath = returnVal.substring(variableStartIdx, variableEndIdx) |
| inputVariables.push(variableFullPath) |
| variableStack.pop() |
| } |
| startIdx += 1 |
| } |
| return inputVariables |
| } |
|
|
| |
| |
| |
| |
| |
| |
| export const getAvailableURLs = async (url: string, limit: number) => { |
| try { |
| const availableUrls: string[] = [] |
|
|
| console.info(`Crawling: ${url}`) |
| availableUrls.push(url) |
|
|
| const response = await axios.get(url) |
| const $ = load(response.data) |
|
|
| const relativeLinks = $("a[href^='/']") |
| console.info(`Available Relative Links: ${relativeLinks.length}`) |
| if (relativeLinks.length === 0) return availableUrls |
|
|
| limit = Math.min(limit + 1, relativeLinks.length) |
| console.info(`True Limit: ${limit}`) |
|
|
| |
| for (let i = 0; availableUrls.length < limit; i++) { |
| if (i === limit) break |
| console.info(`index: ${i}`) |
| const element = relativeLinks[i] |
|
|
| const relativeUrl = $(element).attr('href') |
| if (!relativeUrl) continue |
|
|
| const absoluteUrl = new URL(relativeUrl, url).toString() |
| if (!availableUrls.includes(absoluteUrl)) { |
| availableUrls.push(absoluteUrl) |
| console.info(`Found unique relative link: ${absoluteUrl}`) |
| } |
| } |
|
|
| return availableUrls |
| } catch (err) { |
| throw new Error(`getAvailableURLs: ${err?.message}`) |
| } |
| } |
|
|
| |
| |
| |
| export class CustomChainHandler extends BaseCallbackHandler { |
| name = 'custom_chain_handler' |
| isLLMStarted = false |
| socketIO: Server |
| socketIOClientId = '' |
| skipK = 0 |
| returnSourceDocuments = false |
|
|
| constructor(socketIO: Server, socketIOClientId: string, skipK?: number, returnSourceDocuments?: boolean) { |
| super() |
| this.socketIO = socketIO |
| this.socketIOClientId = socketIOClientId |
| this.skipK = skipK ?? this.skipK |
| this.returnSourceDocuments = returnSourceDocuments ?? this.returnSourceDocuments |
| } |
|
|
| handleLLMStart() { |
| if (this.skipK > 0) this.skipK -= 1 |
| } |
|
|
| handleLLMNewToken(token: string) { |
| if (this.skipK === 0) { |
| if (!this.isLLMStarted) { |
| this.isLLMStarted = true |
| this.socketIO.to(this.socketIOClientId).emit('start', token) |
| } |
| this.socketIO.to(this.socketIOClientId).emit('token', token) |
| } |
| } |
|
|
| handleLLMEnd() { |
| this.socketIO.to(this.socketIOClientId).emit('end') |
| } |
|
|
| handleChainEnd(outputs: ChainValues): void | Promise<void> { |
| if (this.returnSourceDocuments) { |
| this.socketIO.to(this.socketIOClientId).emit('sourceDocuments', outputs?.sourceDocuments) |
| } |
| } |
| } |
|
|
| export const returnJSONStr = (jsonStr: string): string => { |
| let jsonStrArray = jsonStr.split(':') |
|
|
| let wholeString = '' |
| for (let i = 0; i < jsonStrArray.length; i++) { |
| if (jsonStrArray[i].includes(',') && jsonStrArray[i + 1] !== undefined) { |
| const splitValueAndTitle = jsonStrArray[i].split(',') |
| const value = splitValueAndTitle[0] |
| const newTitle = splitValueAndTitle[1] |
| wholeString += handleEscapeDoubleQuote(value) + ',' + newTitle + ':' |
| } else { |
| wholeString += wholeString === '' ? jsonStrArray[i] + ':' : handleEscapeDoubleQuote(jsonStrArray[i]) |
| } |
| } |
| return wholeString |
| } |
|
|
| const handleEscapeDoubleQuote = (value: string): string => { |
| let newValue = '' |
| if (value.includes('"')) { |
| const valueArray = value.split('"') |
| for (let i = 0; i < valueArray.length; i++) { |
| if ((i + 1) % 2 !== 0) { |
| switch (valueArray[i]) { |
| case '': |
| newValue += '"' |
| break |
| case '}': |
| newValue += '"}' |
| break |
| default: |
| newValue += '\\"' + valueArray[i] + '\\"' |
| } |
| } else { |
| newValue += valueArray[i] |
| } |
| } |
| } |
| return newValue === '' ? value : newValue |
| } |
|
|