Merge branch 'main' into feature/ChatHistory2

This commit is contained in:
chungyau97
2023-10-22 07:29:24 +08:00
124 changed files with 3574 additions and 313 deletions
+4
View File
@@ -153,6 +153,10 @@ Flowise support different environment variables to configure your instance. You
[![Deploy to Render](https://render.com/images/deploy-to-render-button.svg)](https://docs.flowiseai.com/deployment/render)
### [Elestio](https://elest.io/open-source/flowiseai)
[![Deploy](https://pub-da36157c854648669813f3f76c526c2b.r2.dev/deploy-on-elestio-black.png)](https://elest.io/open-source/flowiseai)
### [HuggingFace Spaces](https://docs.flowiseai.com/deployment/hugging-face)
<a href="https://huggingface.co/spaces/FlowiseAI/Flowise"><img src="https://huggingface.co/datasets/huggingface/badges/raw/main/open-in-hf-spaces-sm.svg" alt="HuggingFace Spaces"></a>
+6
View File
@@ -10,6 +10,12 @@ services:
- FLOWISE_PASSWORD=${FLOWISE_PASSWORD}
- DEBUG=${DEBUG}
- DATABASE_PATH=${DATABASE_PATH}
- DATABASE_TYPE=${DATABASE_TYPE}
- DATABASE_PORT=${DATABASE_PORT}
- DATABASE_HOST=${DATABASE_HOST}
- DATABASE_NAME=${DATABASE_NAME}
- DATABASE_USER=${DATABASE_USER}
- DATABASE_PASSWORD=${DATABASE_PASSWORD}
- APIKEY_PATH=${APIKEY_PATH}
- SECRETKEY_PATH=${SECRETKEY_PATH}
- FLOWISE_SECRETKEY_OVERWRITE=${FLOWISE_SECRETKEY_OVERWRITE}
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "flowise",
"version": "1.3.6",
"version": "1.3.8",
"private": true,
"homepage": "https://flowiseai.com",
"workspaces": [
@@ -0,0 +1,31 @@
import { INodeParams, INodeCredential } from '../src/Interface'
class ElectricsearchAPI implements INodeCredential {
label: string
name: string
version: number
description: string
inputs: INodeParams[]
constructor() {
this.label = 'Elasticsearch API'
this.name = 'elasticsearchApi'
this.version = 1.0
this.description =
'Refer to <a target="_blank" href="https://www.elastic.co/guide/en/kibana/current/api-keys.html">official guide</a> on how to get an API Key from ElasticSearch'
this.inputs = [
{
label: 'Elasticsearch Endpoint',
name: 'endpoint',
type: 'string'
},
{
label: 'Elasticsearch API Key',
name: 'apiKey',
type: 'password'
}
]
}
}
module.exports = { credClass: ElectricsearchAPI }
@@ -0,0 +1,36 @@
import { INodeParams, INodeCredential } from '../src/Interface'
class ElasticSearchUserPassword implements INodeCredential {
label: string
name: string
version: number
description: string
inputs: INodeParams[]
constructor() {
this.label = 'ElasticSearch User Password'
this.name = 'elasticSearchUserPassword'
this.version = 1.0
this.description =
'Refer to <a target="_blank" href="https://www.elastic.co/guide/en/kibana/current/tutorial-secure-access-to-kibana.html">official guide</a> on how to get User Password from ElasticSearch'
this.inputs = [
{
label: 'Cloud ID',
name: 'cloudId',
type: 'string'
},
{
label: 'ElasticSearch User',
name: 'username',
type: 'string'
},
{
label: 'ElasticSearch Password',
name: 'password',
type: 'password'
}
]
}
}
module.exports = { credClass: ElasticSearchUserPassword }
@@ -0,0 +1,36 @@
import { INodeParams, INodeCredential } from '../src/Interface'
class MomentoCacheApi implements INodeCredential {
label: string
name: string
version: number
description: string
inputs: INodeParams[]
constructor() {
this.label = 'Momento Cache API'
this.name = 'momentoCacheApi'
this.version = 1.0
this.description =
'Refer to <a target="_blank" href="https://docs.momentohq.com/cache/develop/authentication/api-keys">official guide</a> on how to get API key on Momento'
this.inputs = [
{
label: 'Cache',
name: 'momentoCache',
type: 'string'
},
{
label: 'API Key',
name: 'momentoApiKey',
type: 'password'
},
{
label: 'Endpoint',
name: 'momentoEndpoint',
type: 'string'
}
]
}
}
module.exports = { credClass: MomentoCacheApi }
@@ -0,0 +1,43 @@
import { INodeParams, INodeCredential } from '../src/Interface'
class RedisCacheApi implements INodeCredential {
label: string
name: string
version: number
description: string
inputs: INodeParams[]
constructor() {
this.label = 'Redis Cache API'
this.name = 'redisCacheApi'
this.version = 1.0
this.inputs = [
{
label: 'Redis Host',
name: 'redisCacheHost',
type: 'string',
default: '127.0.0.1'
},
{
label: 'Port',
name: 'redisCachePort',
type: 'number',
default: '6789'
},
{
label: 'User',
name: 'redisCacheUser',
type: 'string',
placeholder: '<REDIS_USERNAME>'
},
{
label: 'Password',
name: 'redisCachePwd',
type: 'password',
placeholder: '<REDIS_PASSWORD>'
}
]
}
}
module.exports = { credClass: RedisCacheApi }
@@ -0,0 +1,26 @@
import { INodeParams, INodeCredential } from '../src/Interface'
class UnstructuredApi implements INodeCredential {
label: string
name: string
version: number
description: string
inputs: INodeParams[]
constructor() {
this.label = 'Unstructured API'
this.name = 'unstructuredApi'
this.version = 1.0
this.description =
'Refer to <a target="_blank" href="https://unstructured.io/#get-api-key">official guide</a> on how to get api key on Unstructured'
this.inputs = [
{
label: 'API Key',
name: 'unstructuredAPIKey',
type: 'password'
}
]
}
}
module.exports = { credClass: UnstructuredApi }
@@ -0,0 +1,31 @@
import { INodeParams, INodeCredential } from '../src/Interface'
class UpstashRedisApi implements INodeCredential {
label: string
name: string
version: number
description: string
inputs: INodeParams[]
constructor() {
this.label = 'Upstash Redis API'
this.name = 'upstashRedisApi'
this.version = 1.0
this.description =
'Refer to <a target="_blank" href="https://upstash.com/docs/redis/overall/getstarted">official guide</a> on how to create redis instance and get redis REST URL and Token'
this.inputs = [
{
label: 'Upstash Redis REST URL',
name: 'upstashConnectionUrl',
type: 'string'
},
{
label: 'Token',
name: 'upstashConnectionToken',
type: 'password'
}
]
}
}
module.exports = { credClass: UpstashRedisApi }
@@ -0,0 +1,26 @@
import { INodeParams, INodeCredential } from '../src/Interface'
class UpstashRedisMemoryApi implements INodeCredential {
label: string
name: string
version: number
description: string
inputs: INodeParams[]
constructor() {
this.label = 'Upstash Redis Memory API'
this.name = 'upstashRedisMemoryApi'
this.version = 1.0
this.description =
'Refer to <a target="_blank" href="https://upstash.com/docs/redis/overall/getstarted">official guide</a> on how to create redis instance and get redis REST Token'
this.inputs = [
{
label: 'Upstash Redis REST Token',
name: 'upstashRestToken',
type: 'password'
}
]
}
}
module.exports = { credClass: UpstashRedisMemoryApi }
@@ -95,8 +95,12 @@ class ConversationalAgent_Agents implements INode {
const callbacks = await additionalCallbacks(nodeData, options)
if (options && options.chatHistory) {
memory.chatHistory = mapChatHistory(options)
executor.memory = memory
const chatHistoryClassName = memory.chatHistory.constructor.name
// Only replace when its In-Memory
if (chatHistoryClassName && chatHistoryClassName === 'ChatMessageHistory') {
memory.chatHistory = mapChatHistory(options)
executor.memory = memory
}
}
const result = await executor.call({ input }, [...callbacks])
@@ -82,7 +82,11 @@ class ConversationalRetrievalAgent_Agents implements INode {
if (executor.memory) {
;(executor.memory as any).memoryKey = 'chat_history'
;(executor.memory as any).outputKey = 'output'
;(executor.memory as any).chatHistory = mapChatHistory(options)
const chatHistoryClassName = (executor.memory as any).chatHistory.constructor.name
// Only replace when its In-Memory
if (chatHistoryClassName && chatHistoryClassName === 'ChatMessageHistory') {
;(executor.memory as any).chatHistory = mapChatHistory(options)
}
}
const loggerHandler = new ConsoleCallbackHandler(options.logger)
@@ -81,8 +81,12 @@ class OpenAIFunctionAgent_Agents implements INode {
const memory = nodeData.inputs?.memory as BaseChatMemory
if (options && options.chatHistory) {
memory.chatHistory = mapChatHistory(options)
executor.memory = memory
const chatHistoryClassName = memory.chatHistory.constructor.name
// Only replace when its In-Memory
if (chatHistoryClassName && chatHistoryClassName === 'ChatMessageHistory') {
memory.chatHistory = mapChatHistory(options)
executor.memory = memory
}
}
const loggerHandler = new ConsoleCallbackHandler(options.logger)
@@ -0,0 +1,65 @@
import { getBaseClasses, ICommonObject, INode, INodeData, INodeParams } from '../../../src'
import { BaseCache } from 'langchain/schema'
import hash from 'object-hash'
class InMemoryCache implements INode {
label: string
name: string
version: number
description: string
type: string
icon: string
category: string
baseClasses: string[]
inputs: INodeParams[]
credential: INodeParams
constructor() {
this.label = 'InMemory Cache'
this.name = 'inMemoryCache'
this.version = 1.0
this.type = 'InMemoryCache'
this.description = 'Cache LLM response in memory, will be cleared once app restarted'
this.icon = 'inmemorycache.png'
this.category = 'Cache'
this.baseClasses = [this.type, ...getBaseClasses(InMemoryCacheExtended)]
this.inputs = []
}
async init(nodeData: INodeData, _: string, options: ICommonObject): Promise<any> {
const memoryMap = options.cachePool.getLLMCache(options.chatflowid) ?? new Map()
const inMemCache = new InMemoryCacheExtended(memoryMap)
inMemCache.lookup = async (prompt: string, llmKey: string): Promise<any | null> => {
const memory = options.cachePool.getLLMCache(options.chatflowid) ?? inMemCache.cache
return Promise.resolve(memory.get(getCacheKey(prompt, llmKey)) ?? null)
}
inMemCache.update = async (prompt: string, llmKey: string, value: any): Promise<void> => {
inMemCache.cache.set(getCacheKey(prompt, llmKey), value)
options.cachePool.addLLMCache(options.chatflowid, inMemCache.cache)
}
return inMemCache
}
}
const getCacheKey = (...strings: string[]): string => hash(strings.join('_'))
class InMemoryCacheExtended extends BaseCache {
cache: Map<string, any>
constructor(map: Map<string, any>) {
super()
this.cache = map
}
lookup(prompt: string, llmKey: string): Promise<any | null> {
return Promise.resolve(this.cache.get(getCacheKey(prompt, llmKey)) ?? null)
}
async update(prompt: string, llmKey: string, value: any): Promise<void> {
this.cache.set(getCacheKey(prompt, llmKey), value)
}
}
module.exports = { nodeClass: InMemoryCache }
@@ -0,0 +1,131 @@
import { getBaseClasses, ICommonObject, INode, INodeData, INodeParams } from '../../../src'
import { CacheBackedEmbeddings } from 'langchain/embeddings/cache_backed'
import { Embeddings } from 'langchain/embeddings/base'
import { BaseStore } from 'langchain/schema/storage'
class InMemoryEmbeddingCache implements INode {
label: string
name: string
version: number
description: string
type: string
icon: string
category: string
baseClasses: string[]
inputs: INodeParams[]
credential: INodeParams
constructor() {
this.label = 'InMemory Embedding Cache'
this.name = 'inMemoryEmbeddingCache'
this.version = 1.0
this.type = 'InMemoryEmbeddingCache'
this.description = 'Cache generated Embeddings in memory to avoid needing to recompute them.'
this.icon = 'inmemorycache.png'
this.category = 'Cache'
this.baseClasses = [this.type, ...getBaseClasses(CacheBackedEmbeddings)]
this.inputs = [
{
label: 'Embeddings',
name: 'embeddings',
type: 'Embeddings'
},
{
label: 'Namespace',
name: 'namespace',
type: 'string',
optional: true,
additionalParams: true
}
]
}
async init(nodeData: INodeData, _: string, options: ICommonObject): Promise<any> {
const namespace = nodeData.inputs?.namespace as string
const underlyingEmbeddings = nodeData.inputs?.embeddings as Embeddings
const memoryMap = options.cachePool.getEmbeddingCache(options.chatflowid) ?? {}
const inMemCache = new InMemoryEmbeddingCacheExtended(memoryMap)
inMemCache.mget = async (keys: string[]) => {
const memory = options.cachePool.getEmbeddingCache(options.chatflowid) ?? inMemCache.store
return keys.map((key) => memory[key])
}
inMemCache.mset = async (keyValuePairs: [string, any][]): Promise<void> => {
for (const [key, value] of keyValuePairs) {
inMemCache.store[key] = value
}
options.cachePool.addEmbeddingCache(options.chatflowid, inMemCache.store)
}
inMemCache.mdelete = async (keys: string[]): Promise<void> => {
for (const key of keys) {
delete inMemCache.store[key]
}
options.cachePool.addEmbeddingCache(options.chatflowid, inMemCache.store)
}
return CacheBackedEmbeddings.fromBytesStore(underlyingEmbeddings, inMemCache, {
namespace: namespace
})
}
}
class InMemoryEmbeddingCacheExtended<T = any> extends BaseStore<string, T> {
lc_namespace = ['langchain', 'storage', 'in_memory']
store: Record<string, T> = {}
constructor(map: Record<string, T>) {
super()
this.store = map
}
/**
* Retrieves the values associated with the given keys from the store.
* @param keys Keys to retrieve values for.
* @returns Array of values associated with the given keys.
*/
async mget(keys: string[]) {
return keys.map((key) => this.store[key])
}
/**
* Sets the values for the given keys in the store.
* @param keyValuePairs Array of key-value pairs to set in the store.
* @returns Promise that resolves when all key-value pairs have been set.
*/
async mset(keyValuePairs: [string, T][]): Promise<void> {
for (const [key, value] of keyValuePairs) {
this.store[key] = value
}
}
/**
* Deletes the given keys and their associated values from the store.
* @param keys Keys to delete from the store.
* @returns Promise that resolves when all keys have been deleted.
*/
async mdelete(keys: string[]): Promise<void> {
for (const key of keys) {
delete this.store[key]
}
}
/**
* Asynchronous generator that yields keys from the store. If a prefix is
* provided, it only yields keys that start with the prefix.
* @param prefix Optional prefix to filter keys.
* @returns AsyncGenerator that yields keys from the store.
*/
async *yieldKeys(prefix?: string | undefined): AsyncGenerator<string> {
const keys = Object.keys(this.store)
for (const key of keys) {
if (prefix === undefined || key.startsWith(prefix)) {
yield key
}
}
}
}
module.exports = { nodeClass: InMemoryEmbeddingCache }
Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

@@ -0,0 +1,58 @@
import { getBaseClasses, getCredentialData, getCredentialParam, ICommonObject, INode, INodeData, INodeParams } from '../../../src'
import { MomentoCache as LangchainMomentoCache } from 'langchain/cache/momento'
import { CacheClient, Configurations, CredentialProvider } from '@gomomento/sdk'
class MomentoCache implements INode {
label: string
name: string
version: number
description: string
type: string
icon: string
category: string
baseClasses: string[]
inputs: INodeParams[]
credential: INodeParams
constructor() {
this.label = 'Momento Cache'
this.name = 'momentoCache'
this.version = 1.0
this.type = 'MomentoCache'
this.description = 'Cache LLM response using Momento, a distributed, serverless cache'
this.icon = 'momento.png'
this.category = 'Cache'
this.baseClasses = [this.type, ...getBaseClasses(LangchainMomentoCache)]
this.credential = {
label: 'Connect Credential',
name: 'credential',
type: 'credential',
optional: true,
credentialNames: ['momentoCacheApi']
}
this.inputs = []
}
async init(nodeData: INodeData, _: string, options: ICommonObject): Promise<any> {
const credentialData = await getCredentialData(nodeData.credential ?? '', options)
const apiKey = getCredentialParam('momentoApiKey', credentialData, nodeData)
const cacheName = getCredentialParam('momentoCache', credentialData, nodeData)
// See https://github.com/momentohq/client-sdk-javascript for connection options
const client = new CacheClient({
configuration: Configurations.Laptop.v1(),
credentialProvider: CredentialProvider.fromString({
apiKey: apiKey
}),
defaultTtlSeconds: 60 * 60 * 24
})
let momentoCache = await LangchainMomentoCache.fromProps({
client,
cacheName: cacheName
})
return momentoCache
}
}
module.exports = { nodeClass: MomentoCache }
Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

+118
View File
@@ -0,0 +1,118 @@
import { getBaseClasses, getCredentialData, getCredentialParam, ICommonObject, INode, INodeData, INodeParams } from '../../../src'
import { RedisCache as LangchainRedisCache } from 'langchain/cache/ioredis'
import { Redis } from 'ioredis'
import { Generation, ChatGeneration, StoredGeneration, mapStoredMessageToChatMessage } from 'langchain/schema'
import hash from 'object-hash'
class RedisCache implements INode {
label: string
name: string
version: number
description: string
type: string
icon: string
category: string
baseClasses: string[]
inputs: INodeParams[]
credential: INodeParams
constructor() {
this.label = 'Redis Cache'
this.name = 'redisCache'
this.version = 1.0
this.type = 'RedisCache'
this.description = 'Cache LLM response in Redis, useful for sharing cache across multiple processes or servers'
this.icon = 'redis.svg'
this.category = 'Cache'
this.baseClasses = [this.type, ...getBaseClasses(LangchainRedisCache)]
this.credential = {
label: 'Connect Credential',
name: 'credential',
type: 'credential',
optional: true,
credentialNames: ['redisCacheApi']
}
this.inputs = [
{
label: 'Time to Live (ms)',
name: 'ttl',
type: 'number',
step: 1,
optional: true,
additionalParams: true
}
]
}
async init(nodeData: INodeData, _: string, options: ICommonObject): Promise<any> {
const ttl = nodeData.inputs?.ttl as string
const credentialData = await getCredentialData(nodeData.credential ?? '', options)
const username = getCredentialParam('redisCacheUser', credentialData, nodeData)
const password = getCredentialParam('redisCachePwd', credentialData, nodeData)
const portStr = getCredentialParam('redisCachePort', credentialData, nodeData)
const host = getCredentialParam('redisCacheHost', credentialData, nodeData)
const client = new Redis({
port: portStr ? parseInt(portStr) : 6379,
host,
username,
password
})
const redisClient = new LangchainRedisCache(client)
redisClient.lookup = async (prompt: string, llmKey: string) => {
let idx = 0
let key = getCacheKey(prompt, llmKey, String(idx))
let value = await client.get(key)
const generations: Generation[] = []
while (value) {
const storedGeneration = JSON.parse(value)
generations.push(deserializeStoredGeneration(storedGeneration))
idx += 1
key = getCacheKey(prompt, llmKey, String(idx))
value = await client.get(key)
}
return generations.length > 0 ? generations : null
}
redisClient.update = async (prompt: string, llmKey: string, value: Generation[]) => {
for (let i = 0; i < value.length; i += 1) {
const key = getCacheKey(prompt, llmKey, String(i))
if (ttl !== undefined) {
await client.set(key, JSON.stringify(serializeGeneration(value[i])), 'EX', parseInt(ttl, 10))
} else {
await client.set(key, JSON.stringify(serializeGeneration(value[i])))
}
}
}
return redisClient
}
}
const getCacheKey = (...strings: string[]): string => hash(strings.join('_'))
const deserializeStoredGeneration = (storedGeneration: StoredGeneration) => {
if (storedGeneration.message !== undefined) {
return {
text: storedGeneration.text,
message: mapStoredMessageToChatMessage(storedGeneration.message)
}
} else {
return { text: storedGeneration.text }
}
}
const serializeGeneration = (generation: Generation) => {
const serializedValue: StoredGeneration = {
text: generation.text
}
if ((generation as ChatGeneration).message !== undefined) {
serializedValue.message = (generation as ChatGeneration).message.toDict()
}
return serializedValue
}
module.exports = { nodeClass: RedisCache }
@@ -0,0 +1,90 @@
import { getBaseClasses, getCredentialData, getCredentialParam, ICommonObject, INode, INodeData, INodeParams } from '../../../src'
import { Redis } from 'ioredis'
import { CacheBackedEmbeddings } from 'langchain/embeddings/cache_backed'
import { RedisByteStore } from 'langchain/storage/ioredis'
import { Embeddings } from 'langchain/embeddings/base'
class RedisEmbeddingsCache implements INode {
label: string
name: string
version: number
description: string
type: string
icon: string
category: string
baseClasses: string[]
inputs: INodeParams[]
credential: INodeParams
constructor() {
this.label = 'Redis Embeddings Cache'
this.name = 'redisEmbeddingsCache'
this.version = 1.0
this.type = 'RedisEmbeddingsCache'
this.description = 'Cache generated Embeddings in Redis to avoid needing to recompute them.'
this.icon = 'redis.svg'
this.category = 'Cache'
this.baseClasses = [this.type, ...getBaseClasses(CacheBackedEmbeddings)]
this.credential = {
label: 'Connect Credential',
name: 'credential',
type: 'credential',
optional: true,
credentialNames: ['redisCacheApi']
}
this.inputs = [
{
label: 'Embeddings',
name: 'embeddings',
type: 'Embeddings'
},
{
label: 'Time to Live (ms)',
name: 'ttl',
type: 'number',
step: 10,
default: 60 * 60,
optional: true,
additionalParams: true
},
{
label: 'Namespace',
name: 'namespace',
type: 'string',
optional: true,
additionalParams: true
}
]
}
async init(nodeData: INodeData, _: string, options: ICommonObject): Promise<any> {
let ttl = nodeData.inputs?.ttl as string
const namespace = nodeData.inputs?.namespace as string
const underlyingEmbeddings = nodeData.inputs?.embeddings as Embeddings
const credentialData = await getCredentialData(nodeData.credential ?? '', options)
const username = getCredentialParam('redisCacheUser', credentialData, nodeData)
const password = getCredentialParam('redisCachePwd', credentialData, nodeData)
const portStr = getCredentialParam('redisCachePort', credentialData, nodeData)
const host = getCredentialParam('redisCacheHost', credentialData, nodeData)
const client = new Redis({
port: portStr ? parseInt(portStr) : 6379,
host,
username,
password
})
ttl ??= '3600'
let ttlNumber = parseInt(ttl, 10)
const redisStore = new RedisByteStore({
client: client,
ttl: ttlNumber
})
return CacheBackedEmbeddings.fromBytesStore(underlyingEmbeddings, redisStore, {
namespace: namespace
})
}
}
module.exports = { nodeClass: RedisEmbeddingsCache }
+1
View File
@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 128 128" id="redis"><path fill="#A41E11" d="M121.8 93.1c-6.7 3.5-41.4 17.7-48.8 21.6-7.4 3.9-11.5 3.8-17.3 1s-42.7-17.6-49.4-20.8c-3.3-1.6-5-2.9-5-4.2v-12.7s48-10.5 55.8-13.2c7.8-2.8 10.4-2.9 17-.5s46.1 9.5 52.6 11.9v12.5c0 1.3-1.5 2.7-4.9 4.4z"></path><path fill="#D82C20" d="M121.8 80.5c-6.7 3.5-41.4 17.7-48.8 21.6-7.4 3.9-11.5 3.8-17.3 1-5.8-2.8-42.7-17.7-49.4-20.9-6.6-3.2-6.8-5.4-.3-7.9 6.5-2.6 43.2-17 51-19.7 7.8-2.8 10.4-2.9 17-.5s41.1 16.1 47.6 18.5c6.7 2.4 6.9 4.4.2 7.9z"></path><path fill="#A41E11" d="M121.8 72.5c-6.7 3.5-41.4 17.7-48.8 21.6-7.4 3.8-11.5 3.8-17.3 1-5.8-2.8-42.7-17.7-49.4-20.9-3.3-1.6-5-2.9-5-4.2v-12.7s48-10.5 55.8-13.2c7.8-2.8 10.4-2.9 17-.5s46.1 9.5 52.6 11.9v12.5c0 1.3-1.5 2.7-4.9 4.5z"></path><path fill="#D82C20" d="M121.8 59.8c-6.7 3.5-41.4 17.7-48.8 21.6-7.4 3.8-11.5 3.8-17.3 1-5.8-2.8-42.7-17.7-49.4-20.9s-6.8-5.4-.3-7.9c6.5-2.6 43.2-17 51-19.7 7.8-2.8 10.4-2.9 17-.5s41.1 16.1 47.6 18.5c6.7 2.4 6.9 4.4.2 7.9z"></path><path fill="#A41E11" d="M121.8 51c-6.7 3.5-41.4 17.7-48.8 21.6-7.4 3.8-11.5 3.8-17.3 1-5.8-2.7-42.7-17.6-49.4-20.8-3.3-1.6-5.1-2.9-5.1-4.2v-12.7s48-10.5 55.8-13.2c7.8-2.8 10.4-2.9 17-.5s46.1 9.5 52.6 11.9v12.5c.1 1.3-1.4 2.6-4.8 4.4z"></path><path fill="#D82C20" d="M121.8 38.3c-6.7 3.5-41.4 17.7-48.8 21.6-7.4 3.8-11.5 3.8-17.3 1s-42.7-17.6-49.4-20.8-6.8-5.4-.3-7.9c6.5-2.6 43.2-17 51-19.7 7.8-2.8 10.4-2.9 17-.5s41.1 16.1 47.6 18.5c6.7 2.4 6.9 4.4.2 7.8z"></path><path fill="#fff" d="M80.4 26.1l-10.8 1.2-2.5 5.8-3.9-6.5-12.5-1.1 9.3-3.4-2.8-5.2 8.8 3.4 8.2-2.7-2.2 5.4zM66.5 54.5l-20.3-8.4 29.1-4.4z"></path><ellipse cx="38.4" cy="35.4" fill="#fff" rx="15.5" ry="6"></ellipse><path fill="#7A0C00" d="M93.3 27.7l17.2 6.8-17.2 6.8z"></path><path fill="#AD2115" d="M74.3 35.3l19-7.6v13.6l-1.9.8z"></path></svg>

After

Width:  |  Height:  |  Size: 1.8 KiB

@@ -0,0 +1,50 @@
import { getBaseClasses, getCredentialData, getCredentialParam, ICommonObject, INode, INodeData, INodeParams } from '../../../src'
import { UpstashRedisCache as LangchainUpstashRedisCache } from 'langchain/cache/upstash_redis'
class UpstashRedisCache implements INode {
label: string
name: string
version: number
description: string
type: string
icon: string
category: string
baseClasses: string[]
inputs: INodeParams[]
credential: INodeParams
constructor() {
this.label = 'Upstash Redis Cache'
this.name = 'upstashRedisCache'
this.version = 1.0
this.type = 'UpstashRedisCache'
this.description = 'Cache LLM response in Upstash Redis, serverless data for Redis and Kafka'
this.icon = 'upstash.png'
this.category = 'Cache'
this.baseClasses = [this.type, ...getBaseClasses(LangchainUpstashRedisCache)]
this.credential = {
label: 'Connect Credential',
name: 'credential',
type: 'credential',
optional: true,
credentialNames: ['upstashRedisApi']
}
this.inputs = []
}
async init(nodeData: INodeData, _: string, options: ICommonObject): Promise<any> {
const credentialData = await getCredentialData(nodeData.credential ?? '', options)
const upstashConnectionUrl = getCredentialParam('upstashConnectionUrl', credentialData, nodeData)
const upstashToken = getCredentialParam('upstashConnectionToken', credentialData, nodeData)
const cache = new LangchainUpstashRedisCache({
config: {
url: upstashConnectionUrl,
token: upstashToken
}
})
return cache
}
}
module.exports = { nodeClass: UpstashRedisCache }
Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

@@ -90,7 +90,7 @@ class ConversationChain_Chains implements INode {
verbose: process.env.DEBUG === 'true' ? true : false
}
const chatPrompt = ChatPromptTemplate.fromPromptMessages([
const chatPrompt = ChatPromptTemplate.fromMessages([
SystemMessagePromptTemplate.fromTemplate(prompt ? `${prompt}\n${systemMessage}` : systemMessage),
new MessagesPlaceholder(memory.memoryKey ?? 'chat_history'),
HumanMessagePromptTemplate.fromTemplate('{input}')
@@ -106,8 +106,12 @@ class ConversationChain_Chains implements INode {
const memory = nodeData.inputs?.memory as BufferMemory
if (options && options.chatHistory) {
memory.chatHistory = mapChatHistory(options)
chain.memory = memory
const chatHistoryClassName = memory.chatHistory.constructor.name
// Only replace when its In-Memory
if (chatHistoryClassName && chatHistoryClassName === 'ChatMessageHistory') {
memory.chatHistory = mapChatHistory(options)
chain.memory = memory
}
}
const loggerHandler = new ConsoleCallbackHandler(options.logger)
@@ -179,7 +179,11 @@ class ConversationalRetrievalQAChain_Chains implements INode {
const obj = { question: input }
if (options && options.chatHistory && chain.memory) {
;(chain.memory as any).chatHistory = mapChatHistory(options)
const chatHistoryClassName = (chain.memory as any).chatHistory.constructor.name
// Only replace when its In-Memory
if (chatHistoryClassName && chatHistoryClassName === 'ChatMessageHistory') {
;(chain.memory as any).chatHistory = mapChatHistory(options)
}
}
const loggerHandler = new ConsoleCallbackHandler(options.logger)
@@ -1,5 +1,5 @@
import { ICommonObject, INode, INodeData, INodeParams } from '../../../src/Interface'
import { SqlDatabaseChain, SqlDatabaseChainInput } from 'langchain/chains/sql_db'
import { SqlDatabaseChain, SqlDatabaseChainInput, DEFAULT_SQL_DATABASE_PROMPT } from 'langchain/chains/sql_db'
import { getBaseClasses, getInputVariables } from '../../../src/utils'
import { DataSource } from 'typeorm'
import { SqlDatabase } from 'langchain/sql_db'
@@ -10,25 +10,6 @@ import { DataSourceOptions } from 'typeorm/data-source'
type DatabaseType = 'sqlite' | 'postgres' | 'mssql' | 'mysql'
const defaultPrompt = `Given an input question, first create a syntactically correct {dialect} query to run, then look at the results of the query and return the answer. Unless the user specifies in his question a specific number of examples he wishes to obtain, always limit your query to at most {top_k} results. You can order the results by a relevant column to return the most interesting examples in the database.
Never query for all the columns from a specific table, only ask for a the few relevant columns given the question.
Pay attention to use only the column names that you can see in the schema description. Be careful to not query for columns that do not exist. Also, pay attention to which column is in which table.
Use the following format:
Question: "Question here"
SQLQuery: "SQL Query to run"
SQLResult: "Result of the SQLQuery"
Answer: "Final answer here"
Only use the tables listed below.
{table_info}
Question: {input}`
class SqlDatabaseChain_Chains implements INode {
label: string
name: string
@@ -131,7 +112,7 @@ class SqlDatabaseChain_Chains implements INode {
warning:
'Prompt must include 3 input variables: {input}, {dialect}, {table_info}. You can refer to official guide from description above',
rows: 4,
placeholder: defaultPrompt,
placeholder: DEFAULT_SQL_DATABASE_PROMPT.template + DEFAULT_SQL_DATABASE_PROMPT.templateFormat,
additionalParams: true,
optional: true
}
@@ -2,6 +2,8 @@ import { ICommonObject, INode, INodeData, INodeParams } from '../../../src/Inter
import { getBaseClasses, getCredentialData, getCredentialParam } from '../../../src/utils'
import { ChatBedrock } from 'langchain/chat_models/bedrock'
import { BaseBedrockInput } from 'langchain/dist/util/bedrock'
import { BaseCache } from 'langchain/schema'
import { BaseLLMParams } from 'langchain/llms/base'
/**
* I had to run the following to build the component
@@ -25,11 +27,11 @@ class AWSChatBedrock_ChatModels implements INode {
constructor() {
this.label = 'AWS Bedrock'
this.name = 'awsChatBedrock'
this.version = 1.1
this.version = 2.0
this.type = 'AWSChatBedrock'
this.icon = 'awsBedrock.png'
this.category = 'Chat Models'
this.description = 'Wrapper around AWS Bedrock large language models'
this.description = 'Wrapper around AWS Bedrock large language models that use the Chat endpoint'
this.baseClasses = [this.type, ...getBaseClasses(ChatBedrock)]
this.credential = {
label: 'AWS Credential',
@@ -39,6 +41,12 @@ class AWSChatBedrock_ChatModels implements INode {
optional: true
}
this.inputs = [
{
label: 'Cache',
name: 'cache',
type: 'BaseCache',
optional: true
},
{
label: 'Region',
name: 'region',
@@ -80,27 +88,18 @@ class AWSChatBedrock_ChatModels implements INode {
{ label: 'us-west-1', name: 'us-west-1' },
{ label: 'us-west-2', name: 'us-west-2' }
],
default: 'us-east-1',
optional: false
default: 'us-east-1'
},
{
label: 'Model Name',
name: 'model',
type: 'options',
options: [
{ label: 'amazon.titan-tg1-large', name: 'amazon.titan-tg1-large' },
{ label: 'amazon.titan-e1t-medium', name: 'amazon.titan-e1t-medium' },
{ label: 'stability.stable-diffusion-xl', name: 'stability.stable-diffusion-xl' },
{ label: 'ai21.j2-grande-instruct', name: 'ai21.j2-grande-instruct' },
{ label: 'ai21.j2-jumbo-instruct', name: 'ai21.j2-jumbo-instruct' },
{ label: 'ai21.j2-mid', name: 'ai21.j2-mid' },
{ label: 'ai21.j2-ultra', name: 'ai21.j2-ultra' },
{ label: 'anthropic.claude-instant-v1', name: 'anthropic.claude-instant-v1' },
{ label: 'anthropic.claude-v1', name: 'anthropic.claude-v1' },
{ label: 'anthropic.claude-v2', name: 'anthropic.claude-v2' }
],
default: 'anthropic.claude-v2',
optional: false
default: 'anthropic.claude-v2'
},
{
label: 'Temperature',
@@ -109,8 +108,7 @@ class AWSChatBedrock_ChatModels implements INode {
step: 0.1,
description: 'Temperature parameter may not apply to certain model. Please check available model parameters',
optional: true,
default: 0.7,
additionalParams: false
default: 0.7
},
{
label: 'Max Tokens to Sample',
@@ -118,9 +116,8 @@ class AWSChatBedrock_ChatModels implements INode {
type: 'number',
step: 10,
description: 'Max Tokens parameter may not apply to certain model. Please check available model parameters',
optional: false,
default: 200,
additionalParams: false
optional: true,
default: 200
}
]
}
@@ -130,8 +127,9 @@ class AWSChatBedrock_ChatModels implements INode {
const iModel = nodeData.inputs?.model as string
const iTemperature = nodeData.inputs?.temperature as string
const iMax_tokens_to_sample = nodeData.inputs?.max_tokens_to_sample as string
const cache = nodeData.inputs?.cache as BaseCache
const obj: BaseBedrockInput = {
const obj: BaseBedrockInput & BaseLLMParams = {
region: iRegion,
model: iModel,
maxTokens: parseInt(iMax_tokens_to_sample, 10),
@@ -157,6 +155,7 @@ class AWSChatBedrock_ChatModels implements INode {
sessionToken: credentialApiSession
}
}
if (cache) obj.cache = cache
const amazonBedrock = new ChatBedrock(obj)
return amazonBedrock
@@ -2,6 +2,8 @@ import { OpenAIBaseInput } from 'langchain/dist/types/openai-types'
import { ICommonObject, INode, INodeData, INodeParams } from '../../../src/Interface'
import { getBaseClasses, getCredentialData, getCredentialParam } from '../../../src/utils'
import { AzureOpenAIInput, ChatOpenAI } from 'langchain/chat_models/openai'
import { BaseCache } from 'langchain/schema'
import { BaseLLMParams } from 'langchain/llms/base'
class AzureChatOpenAI_ChatModels implements INode {
label: string
@@ -18,7 +20,7 @@ class AzureChatOpenAI_ChatModels implements INode {
constructor() {
this.label = 'Azure ChatOpenAI'
this.name = 'azureChatOpenAI'
this.version = 1.0
this.version = 2.0
this.type = 'AzureChatOpenAI'
this.icon = 'Azure.svg'
this.category = 'Chat Models'
@@ -31,6 +33,12 @@ class AzureChatOpenAI_ChatModels implements INode {
credentialNames: ['azureOpenAIApi']
}
this.inputs = [
{
label: 'Cache',
name: 'cache',
type: 'BaseCache',
optional: true
},
{
label: 'Model Name',
name: 'modelName',
@@ -107,6 +115,7 @@ class AzureChatOpenAI_ChatModels implements INode {
const presencePenalty = nodeData.inputs?.presencePenalty as string
const timeout = nodeData.inputs?.timeout as string
const streaming = nodeData.inputs?.streaming as boolean
const cache = nodeData.inputs?.cache as BaseCache
const credentialData = await getCredentialData(nodeData.credential ?? '', options)
const azureOpenAIApiKey = getCredentialParam('azureOpenAIApiKey', credentialData, nodeData)
@@ -114,7 +123,7 @@ class AzureChatOpenAI_ChatModels implements INode {
const azureOpenAIApiDeploymentName = getCredentialParam('azureOpenAIApiDeploymentName', credentialData, nodeData)
const azureOpenAIApiVersion = getCredentialParam('azureOpenAIApiVersion', credentialData, nodeData)
const obj: Partial<AzureOpenAIInput> & Partial<OpenAIBaseInput> = {
const obj: Partial<AzureOpenAIInput> & BaseLLMParams & Partial<OpenAIBaseInput> = {
temperature: parseFloat(temperature),
modelName,
azureOpenAIApiKey,
@@ -128,6 +137,7 @@ class AzureChatOpenAI_ChatModels implements INode {
if (frequencyPenalty) obj.frequencyPenalty = parseFloat(frequencyPenalty)
if (presencePenalty) obj.presencePenalty = parseFloat(presencePenalty)
if (timeout) obj.timeout = parseInt(timeout, 10)
if (cache) obj.cache = cache
const model = new ChatOpenAI(obj)
return model
@@ -1,6 +1,7 @@
import { INode, INodeData, INodeParams } from '../../../src/Interface'
import { getBaseClasses } from '../../../src/utils'
import { NIBittensorChatModel, BittensorInput } from 'langchain/experimental/chat_models/bittensor'
import { BaseCache } from 'langchain/schema'
class Bittensor_ChatModels implements INode {
label: string
@@ -16,13 +17,19 @@ class Bittensor_ChatModels implements INode {
constructor() {
this.label = 'NIBittensorChat'
this.name = 'NIBittensorChatModel'
this.version = 1.0
this.version = 2.0
this.type = 'BittensorChat'
this.icon = 'logo.png'
this.category = 'Chat Models'
this.description = 'Wrapper around Bittensor subnet 1 large language models'
this.baseClasses = [this.type, ...getBaseClasses(NIBittensorChatModel)]
this.inputs = [
{
label: 'Cache',
name: 'cache',
type: 'BaseCache',
optional: true
},
{
label: 'System prompt',
name: 'system_prompt',
@@ -35,9 +42,13 @@ class Bittensor_ChatModels implements INode {
async init(nodeData: INodeData, _: string): Promise<any> {
const system_prompt = nodeData.inputs?.system_prompt as string
const cache = nodeData.inputs?.cache as BaseCache
const obj: Partial<BittensorInput> = {
systemPrompt: system_prompt
}
if (cache) obj.cache = cache
const model = new NIBittensorChatModel(obj)
return model
}
@@ -1,6 +1,8 @@
import { ICommonObject, INode, INodeData, INodeParams } from '../../../src/Interface'
import { getBaseClasses, getCredentialData, getCredentialParam } from '../../../src/utils'
import { AnthropicInput, ChatAnthropic } from 'langchain/chat_models/anthropic'
import { BaseCache } from 'langchain/schema'
import { BaseLLMParams } from 'langchain/llms/base'
class ChatAnthropic_ChatModels implements INode {
label: string
@@ -17,7 +19,7 @@ class ChatAnthropic_ChatModels implements INode {
constructor() {
this.label = 'ChatAnthropic'
this.name = 'chatAnthropic'
this.version = 1.0
this.version = 2.0
this.type = 'ChatAnthropic'
this.icon = 'chatAnthropic.png'
this.category = 'Chat Models'
@@ -30,6 +32,12 @@ class ChatAnthropic_ChatModels implements INode {
credentialNames: ['anthropicApi']
}
this.inputs = [
{
label: 'Cache',
name: 'cache',
type: 'BaseCache',
optional: true
},
{
label: 'Model Name',
name: 'modelName',
@@ -135,11 +143,12 @@ class ChatAnthropic_ChatModels implements INode {
const topP = nodeData.inputs?.topP as string
const topK = nodeData.inputs?.topK as string
const streaming = nodeData.inputs?.streaming as boolean
const cache = nodeData.inputs?.cache as BaseCache
const credentialData = await getCredentialData(nodeData.credential ?? '', options)
const anthropicApiKey = getCredentialParam('anthropicApiKey', credentialData, nodeData)
const obj: Partial<AnthropicInput> & { anthropicApiKey?: string } = {
const obj: Partial<AnthropicInput> & BaseLLMParams & { anthropicApiKey?: string } = {
temperature: parseFloat(temperature),
modelName,
anthropicApiKey,
@@ -149,6 +158,7 @@ class ChatAnthropic_ChatModels implements INode {
if (maxTokensToSample) obj.maxTokensToSample = parseInt(maxTokensToSample, 10)
if (topP) obj.topP = parseFloat(topP)
if (topK) obj.topK = parseFloat(topK)
if (cache) obj.cache = cache
const model = new ChatAnthropic(obj)
return model
@@ -1,6 +1,7 @@
import { ICommonObject, INode, INodeData, INodeParams } from '../../../src/Interface'
import { getBaseClasses, getCredentialData, getCredentialParam } from '../../../src/utils'
import { ChatGooglePaLM, GooglePaLMChatInput } from 'langchain/chat_models/googlepalm'
import { BaseCache } from 'langchain/schema'
class ChatGooglePaLM_ChatModels implements INode {
label: string
@@ -17,7 +18,7 @@ class ChatGooglePaLM_ChatModels implements INode {
constructor() {
this.label = 'ChatGooglePaLM'
this.name = 'chatGooglePaLM'
this.version = 1.0
this.version = 2.0
this.type = 'ChatGooglePaLM'
this.icon = 'Google_PaLM_Logo.svg'
this.category = 'Chat Models'
@@ -30,6 +31,12 @@ class ChatGooglePaLM_ChatModels implements INode {
credentialNames: ['googleMakerSuite']
}
this.inputs = [
{
label: 'Cache',
name: 'cache',
type: 'BaseCache',
optional: true
},
{
label: 'Model Name',
name: 'modelName',
@@ -96,6 +103,7 @@ class ChatGooglePaLM_ChatModels implements INode {
const temperature = nodeData.inputs?.temperature as string
const topP = nodeData.inputs?.topP as string
const topK = nodeData.inputs?.topK as string
const cache = nodeData.inputs?.cache as BaseCache
const credentialData = await getCredentialData(nodeData.credential ?? '', options)
const googleMakerSuiteKey = getCredentialParam('googleMakerSuiteKey', credentialData, nodeData)
@@ -108,6 +116,7 @@ class ChatGooglePaLM_ChatModels implements INode {
if (topP) obj.topP = parseFloat(topP)
if (topK) obj.topK = parseFloat(topK)
if (cache) obj.cache = cache
const model = new ChatGooglePaLM(obj)
return model
@@ -2,6 +2,7 @@ import { ICommonObject, INode, INodeData, INodeParams } from '../../../src/Inter
import { getBaseClasses, getCredentialData, getCredentialParam } from '../../../src/utils'
import { ChatGoogleVertexAI, GoogleVertexAIChatInput } from 'langchain/chat_models/googlevertexai'
import { GoogleAuthOptions } from 'google-auth-library'
import { BaseCache } from 'langchain/schema'
class GoogleVertexAI_ChatModels implements INode {
label: string
@@ -18,7 +19,7 @@ class GoogleVertexAI_ChatModels implements INode {
constructor() {
this.label = 'ChatGoogleVertexAI'
this.name = 'chatGoogleVertexAI'
this.version = 1.0
this.version = 2.0
this.type = 'ChatGoogleVertexAI'
this.icon = 'vertexai.svg'
this.category = 'Chat Models'
@@ -34,6 +35,12 @@ class GoogleVertexAI_ChatModels implements INode {
'Google Vertex AI credential. If you are using a GCP service like Cloud Run, or if you have installed default credentials on your local machine, you do not need to set this credential.'
}
this.inputs = [
{
label: 'Cache',
name: 'cache',
type: 'BaseCache',
optional: true
},
{
label: 'Model Name',
name: 'modelName',
@@ -113,6 +120,7 @@ class GoogleVertexAI_ChatModels implements INode {
const modelName = nodeData.inputs?.modelName as string
const maxOutputTokens = nodeData.inputs?.maxOutputTokens as string
const topP = nodeData.inputs?.topP as string
const cache = nodeData.inputs?.cache as BaseCache
const obj: GoogleVertexAIChatInput<GoogleAuthOptions> = {
temperature: parseFloat(temperature),
@@ -122,6 +130,7 @@ class GoogleVertexAI_ChatModels implements INode {
if (maxOutputTokens) obj.maxOutputTokens = parseInt(maxOutputTokens, 10)
if (topP) obj.topP = parseFloat(topP)
if (cache) obj.cache = cache
const model = new ChatGoogleVertexAI(obj)
return model
@@ -1,6 +1,7 @@
import { ICommonObject, INode, INodeData, INodeParams } from '../../../src/Interface'
import { getBaseClasses, getCredentialData, getCredentialParam } from '../../../src/utils'
import { HFInput, HuggingFaceInference } from './core'
import { BaseCache } from 'langchain/schema'
class ChatHuggingFace_ChatModels implements INode {
label: string
@@ -17,7 +18,7 @@ class ChatHuggingFace_ChatModels implements INode {
constructor() {
this.label = 'ChatHuggingFace'
this.name = 'chatHuggingFace'
this.version = 1.0
this.version = 2.0
this.type = 'ChatHuggingFace'
this.icon = 'huggingface.png'
this.category = 'Chat Models'
@@ -30,6 +31,12 @@ class ChatHuggingFace_ChatModels implements INode {
credentialNames: ['huggingFaceApi']
}
this.inputs = [
{
label: 'Cache',
name: 'cache',
type: 'BaseCache',
optional: true
},
{
label: 'Model',
name: 'model',
@@ -102,6 +109,7 @@ class ChatHuggingFace_ChatModels implements INode {
const hfTopK = nodeData.inputs?.hfTopK as string
const frequencyPenalty = nodeData.inputs?.frequencyPenalty as string
const endpoint = nodeData.inputs?.endpoint as string
const cache = nodeData.inputs?.cache as BaseCache
const credentialData = await getCredentialData(nodeData.credential ?? '', options)
const huggingFaceApiKey = getCredentialParam('huggingFaceApiKey', credentialData, nodeData)
@@ -119,6 +127,7 @@ class ChatHuggingFace_ChatModels implements INode {
if (endpoint) obj.endpoint = endpoint
const huggingFace = new HuggingFaceInference(obj)
if (cache) huggingFace.cache = cache
return huggingFace
}
}
@@ -2,6 +2,8 @@ import { INode, INodeData, INodeParams } from '../../../src/Interface'
import { getBaseClasses } from '../../../src/utils'
import { OpenAIChat } from 'langchain/llms/openai'
import { OpenAIChatInput } from 'langchain/chat_models/openai'
import { BaseCache } from 'langchain/schema'
import { BaseLLMParams } from 'langchain/llms/base'
class ChatLocalAI_ChatModels implements INode {
label: string
@@ -17,13 +19,19 @@ class ChatLocalAI_ChatModels implements INode {
constructor() {
this.label = 'ChatLocalAI'
this.name = 'chatLocalAI'
this.version = 1.0
this.version = 2.0
this.type = 'ChatLocalAI'
this.icon = 'localai.png'
this.category = 'Chat Models'
this.description = 'Use local LLMs like llama.cpp, gpt4all using LocalAI'
this.baseClasses = [this.type, 'BaseChatModel', ...getBaseClasses(OpenAIChat)]
this.inputs = [
{
label: 'Cache',
name: 'cache',
type: 'BaseCache',
optional: true
},
{
label: 'Base Path',
name: 'basePath',
@@ -78,8 +86,9 @@ class ChatLocalAI_ChatModels implements INode {
const topP = nodeData.inputs?.topP as string
const timeout = nodeData.inputs?.timeout as string
const basePath = nodeData.inputs?.basePath as string
const cache = nodeData.inputs?.cache as BaseCache
const obj: Partial<OpenAIChatInput> & { openAIApiKey?: string } = {
const obj: Partial<OpenAIChatInput> & BaseLLMParams & { openAIApiKey?: string } = {
temperature: parseFloat(temperature),
modelName,
openAIApiKey: 'sk-'
@@ -88,6 +97,7 @@ class ChatLocalAI_ChatModels implements INode {
if (maxTokens) obj.maxTokens = parseInt(maxTokens, 10)
if (topP) obj.topP = parseFloat(topP)
if (timeout) obj.timeout = parseInt(timeout, 10)
if (cache) obj.cache = cache
const model = new OpenAIChat(obj, { basePath })
@@ -0,0 +1,241 @@
import { INode, INodeData, INodeParams } from '../../../src/Interface'
import { getBaseClasses } from '../../../src/utils'
import { ChatOllama } from 'langchain/chat_models/ollama'
import { BaseCache } from 'langchain/schema'
import { OllamaInput } from 'langchain/dist/util/ollama'
import { BaseLLMParams } from 'langchain/llms/base'
class ChatOllama_ChatModels implements INode {
label: string
name: string
version: number
type: string
icon: string
category: string
description: string
baseClasses: string[]
credential: INodeParams
inputs: INodeParams[]
constructor() {
this.label = 'ChatOllama'
this.name = 'chatOllama'
this.version = 2.0
this.type = 'ChatOllama'
this.icon = 'ollama.png'
this.category = 'Chat Models'
this.description = 'Chat completion using open-source LLM on Ollama'
this.baseClasses = [this.type, ...getBaseClasses(ChatOllama)]
this.inputs = [
{
label: 'Cache',
name: 'cache',
type: 'BaseCache',
optional: true
},
{
label: 'Base URL',
name: 'baseUrl',
type: 'string',
default: 'http://localhost:11434'
},
{
label: 'Model Name',
name: 'modelName',
type: 'string',
placeholder: 'llama2'
},
{
label: 'Temperature',
name: 'temperature',
type: 'number',
description:
'The temperature of the model. Increasing the temperature will make the model answer more creatively. (Default: 0.8). Refer to <a target="_blank" href="https://github.com/jmorganca/ollama/blob/main/docs/modelfile.md#valid-parameters-and-values">docs</a> for more details',
step: 0.1,
default: 0.9,
optional: true
},
{
label: 'Top P',
name: 'topP',
type: 'number',
description:
'Works together with top-k. A higher value (e.g., 0.95) will lead to more diverse text, while a lower value (e.g., 0.5) will generate more focused and conservative text. (Default: 0.9). Refer to <a target="_blank" href="https://github.com/jmorganca/ollama/blob/main/docs/modelfile.md#valid-parameters-and-values">docs</a> for more details',
step: 0.1,
optional: true,
additionalParams: true
},
{
label: 'Top K',
name: 'topK',
type: 'number',
description:
'Reduces the probability of generating nonsense. A higher value (e.g. 100) will give more diverse answers, while a lower value (e.g. 10) will be more conservative. (Default: 40). Refer to <a target="_blank" href="https://github.com/jmorganca/ollama/blob/main/docs/modelfile.md#valid-parameters-and-values">docs</a> for more details',
step: 1,
optional: true,
additionalParams: true
},
{
label: 'Mirostat',
name: 'mirostat',
type: 'number',
description:
'Enable Mirostat sampling for controlling perplexity. (default: 0, 0 = disabled, 1 = Mirostat, 2 = Mirostat 2.0). Refer to <a target="_blank" href="https://github.com/jmorganca/ollama/blob/main/docs/modelfile.md#valid-parameters-and-values">docs</a> for more details',
step: 1,
optional: true,
additionalParams: true
},
{
label: 'Mirostat ETA',
name: 'mirostatEta',
type: 'number',
description:
'Influences how quickly the algorithm responds to feedback from the generated text. A lower learning rate will result in slower adjustments, while a higher learning rate will make the algorithm more responsive. (Default: 0.1) Refer to <a target="_blank" href="https://github.com/jmorganca/ollama/blob/main/docs/modelfile.md#valid-parameters-and-values">docs</a> for more details',
step: 0.1,
optional: true,
additionalParams: true
},
{
label: 'Mirostat TAU',
name: 'mirostatTau',
type: 'number',
description:
'Controls the balance between coherence and diversity of the output. A lower value will result in more focused and coherent text. (Default: 5.0) Refer to <a target="_blank" href="https://github.com/jmorganca/ollama/blob/main/docs/modelfile.md#valid-parameters-and-values">docs</a> for more details',
step: 0.1,
optional: true,
additionalParams: true
},
{
label: 'Context Window Size',
name: 'numCtx',
type: 'number',
description:
'Sets the size of the context window used to generate the next token. (Default: 2048) Refer to <a target="_blank" href="https://github.com/jmorganca/ollama/blob/main/docs/modelfile.md#valid-parameters-and-values">docs</a> for more details',
step: 1,
optional: true,
additionalParams: true
},
{
label: 'Number of GQA groups',
name: 'numGqa',
type: 'number',
description:
'The number of GQA groups in the transformer layer. Required for some models, for example it is 8 for llama2:70b. Refer to <a target="_blank" href="https://github.com/jmorganca/ollama/blob/main/docs/modelfile.md#valid-parameters-and-values">docs</a> for more details',
step: 1,
optional: true,
additionalParams: true
},
{
label: 'Number of GPU',
name: 'numGpu',
type: 'number',
description:
'The number of layers to send to the GPU(s). On macOS it defaults to 1 to enable metal support, 0 to disable. Refer to <a target="_blank" href="https://github.com/jmorganca/ollama/blob/main/docs/modelfile.md#valid-parameters-and-values">docs</a> for more details',
step: 1,
optional: true,
additionalParams: true
},
{
label: 'Number of Thread',
name: 'numThread',
type: 'number',
description:
'Sets the number of threads to use during computation. By default, Ollama will detect this for optimal performance. It is recommended to set this value to the number of physical CPU cores your system has (as opposed to the logical number of cores). Refer to <a target="_blank" href="https://github.com/jmorganca/ollama/blob/main/docs/modelfile.md#valid-parameters-and-values">docs</a> for more details',
step: 1,
optional: true,
additionalParams: true
},
{
label: 'Repeat Last N',
name: 'repeatLastN',
type: 'number',
description:
'Sets how far back for the model to look back to prevent repetition. (Default: 64, 0 = disabled, -1 = num_ctx). Refer to <a target="_blank" href="https://github.com/jmorganca/ollama/blob/main/docs/modelfile.md#valid-parameters-and-values">docs</a> for more details',
step: 1,
optional: true,
additionalParams: true
},
{
label: 'Repeat Penalty',
name: 'repeatPenalty',
type: 'number',
description:
'Sets how strongly to penalize repetitions. A higher value (e.g., 1.5) will penalize repetitions more strongly, while a lower value (e.g., 0.9) will be more lenient. (Default: 1.1). Refer to <a target="_blank" href="https://github.com/jmorganca/ollama/blob/main/docs/modelfile.md#valid-parameters-and-values">docs</a> for more details',
step: 0.1,
optional: true,
additionalParams: true
},
{
label: 'Stop Sequence',
name: 'stop',
type: 'string',
rows: 4,
placeholder: 'AI assistant:',
description:
'Sets the stop sequences to use. Use comma to seperate different sequences. Refer to <a target="_blank" href="https://github.com/jmorganca/ollama/blob/main/docs/modelfile.md#valid-parameters-and-values">docs</a> for more details',
optional: true,
additionalParams: true
},
{
label: 'Tail Free Sampling',
name: 'tfsZ',
type: 'number',
description:
'Tail free sampling is used to reduce the impact of less probable tokens from the output. A higher value (e.g., 2.0) will reduce the impact more, while a value of 1.0 disables this setting. (Default: 1). Refer to <a target="_blank" href="https://github.com/jmorganca/ollama/blob/main/docs/modelfile.md#valid-parameters-and-values">docs</a> for more details',
step: 0.1,
optional: true,
additionalParams: true
}
]
}
async init(nodeData: INodeData): Promise<any> {
const temperature = nodeData.inputs?.temperature as string
const baseUrl = nodeData.inputs?.baseUrl as string
const modelName = nodeData.inputs?.modelName as string
const topP = nodeData.inputs?.topP as string
const topK = nodeData.inputs?.topK as string
const mirostat = nodeData.inputs?.mirostat as string
const mirostatEta = nodeData.inputs?.mirostatEta as string
const mirostatTau = nodeData.inputs?.mirostatTau as string
const numCtx = nodeData.inputs?.numCtx as string
const numGqa = nodeData.inputs?.numGqa as string
const numGpu = nodeData.inputs?.numGpu as string
const numThread = nodeData.inputs?.numThread as string
const repeatLastN = nodeData.inputs?.repeatLastN as string
const repeatPenalty = nodeData.inputs?.repeatPenalty as string
const stop = nodeData.inputs?.stop as string
const tfsZ = nodeData.inputs?.tfsZ as string
const cache = nodeData.inputs?.cache as BaseCache
const obj: OllamaInput & BaseLLMParams = {
baseUrl,
temperature: parseFloat(temperature),
model: modelName
}
if (topP) obj.topP = parseFloat(topP)
if (topK) obj.topK = parseFloat(topK)
if (mirostat) obj.mirostat = parseFloat(mirostat)
if (mirostatEta) obj.mirostatEta = parseFloat(mirostatEta)
if (mirostatTau) obj.mirostatTau = parseFloat(mirostatTau)
if (numCtx) obj.numCtx = parseFloat(numCtx)
if (numGqa) obj.numGqa = parseFloat(numGqa)
if (numGpu) obj.numGpu = parseFloat(numGpu)
if (numThread) obj.numThread = parseFloat(numThread)
if (repeatLastN) obj.repeatLastN = parseFloat(repeatLastN)
if (repeatPenalty) obj.repeatPenalty = parseFloat(repeatPenalty)
if (tfsZ) obj.tfsZ = parseFloat(tfsZ)
if (stop) {
const stopSequences = stop.split(',')
obj.stop = stopSequences
}
if (cache) obj.cache = cache
const model = new ChatOllama(obj)
return model
}
}
module.exports = { nodeClass: ChatOllama_ChatModels }
Binary file not shown.

After

Width:  |  Height:  |  Size: 7.3 KiB

@@ -1,6 +1,8 @@
import { ICommonObject, INode, INodeData, INodeParams } from '../../../src/Interface'
import { getBaseClasses, getCredentialData, getCredentialParam } from '../../../src/utils'
import { ChatOpenAI, OpenAIChatInput } from 'langchain/chat_models/openai'
import { BaseCache } from 'langchain/schema'
import { BaseLLMParams } from 'langchain/llms/base'
class ChatOpenAI_ChatModels implements INode {
label: string
@@ -17,7 +19,7 @@ class ChatOpenAI_ChatModels implements INode {
constructor() {
this.label = 'ChatOpenAI'
this.name = 'chatOpenAI'
this.version = 1.0
this.version = 2.0
this.type = 'ChatOpenAI'
this.icon = 'openai.png'
this.category = 'Chat Models'
@@ -30,6 +32,12 @@ class ChatOpenAI_ChatModels implements INode {
credentialNames: ['openAIApi']
}
this.inputs = [
{
label: 'Cache',
name: 'cache',
type: 'BaseCache',
optional: true
},
{
label: 'Model Name',
name: 'modelName',
@@ -151,7 +159,9 @@ class ChatOpenAI_ChatModels implements INode {
const credentialData = await getCredentialData(nodeData.credential ?? '', options)
const openAIApiKey = getCredentialParam('openAIApiKey', credentialData, nodeData)
const obj: Partial<OpenAIChatInput> & { openAIApiKey?: string } = {
const cache = nodeData.inputs?.cache as BaseCache
const obj: Partial<OpenAIChatInput> & BaseLLMParams & { openAIApiKey?: string } = {
temperature: parseFloat(temperature),
modelName,
openAIApiKey,
@@ -163,6 +173,7 @@ class ChatOpenAI_ChatModels implements INode {
if (frequencyPenalty) obj.frequencyPenalty = parseFloat(frequencyPenalty)
if (presencePenalty) obj.presencePenalty = parseFloat(presencePenalty)
if (timeout) obj.timeout = parseInt(timeout, 10)
if (cache) obj.cache = cache
let parsedBaseOptions: any | undefined = undefined
@@ -1,6 +1,8 @@
import { ICommonObject, INode, INodeData, INodeParams } from '../../../src/Interface'
import { getBaseClasses, getCredentialData, getCredentialParam } from '../../../src/utils'
import { ChatOpenAI, OpenAIChatInput } from 'langchain/chat_models/openai'
import { BaseCache } from 'langchain/schema'
import { BaseLLMParams } from 'langchain/llms/base'
class ChatOpenAICustom_ChatModels implements INode {
label: string
@@ -17,7 +19,7 @@ class ChatOpenAICustom_ChatModels implements INode {
constructor() {
this.label = 'ChatOpenAI Custom'
this.name = 'chatOpenAICustom'
this.version = 1.0
this.version = 2.0
this.type = 'ChatOpenAI-Custom'
this.icon = 'openai.png'
this.category = 'Chat Models'
@@ -31,6 +33,12 @@ class ChatOpenAICustom_ChatModels implements INode {
optional: true
}
this.inputs = [
{
label: 'Cache',
name: 'cache',
type: 'BaseCache',
optional: true
},
{
label: 'Model Name',
name: 'modelName',
@@ -113,11 +121,12 @@ class ChatOpenAICustom_ChatModels implements INode {
const streaming = nodeData.inputs?.streaming as boolean
const basePath = nodeData.inputs?.basepath as string
const baseOptions = nodeData.inputs?.baseOptions
const cache = nodeData.inputs?.cache as BaseCache
const credentialData = await getCredentialData(nodeData.credential ?? '', options)
const openAIApiKey = getCredentialParam('openAIApiKey', credentialData, nodeData)
const obj: Partial<OpenAIChatInput> & { openAIApiKey?: string } = {
const obj: Partial<OpenAIChatInput> & BaseLLMParams & { openAIApiKey?: string } = {
temperature: parseFloat(temperature),
modelName,
openAIApiKey,
@@ -129,6 +138,7 @@ class ChatOpenAICustom_ChatModels implements INode {
if (frequencyPenalty) obj.frequencyPenalty = parseFloat(frequencyPenalty)
if (presencePenalty) obj.presencePenalty = parseFloat(presencePenalty)
if (timeout) obj.timeout = parseInt(timeout, 10)
if (cache) obj.cache = cache
let parsedBaseOptions: any | undefined = undefined
@@ -1,6 +1,7 @@
import { INode, INodeData, INodeParams } from '../../../src/Interface'
import { INode, INodeData, INodeOutputsValue, INodeParams } from '../../../src/Interface'
import { TextSplitter } from 'langchain/text_splitter'
import { Document } from 'langchain/document'
import { handleEscapeCharacters } from '../../../src'
class PlainText_DocumentLoaders implements INode {
label: string
@@ -12,11 +13,12 @@ class PlainText_DocumentLoaders implements INode {
category: string
baseClasses: string[]
inputs: INodeParams[]
outputs: INodeOutputsValue[]
constructor() {
this.label = 'Plain Text'
this.name = 'plainText'
this.version = 1.0
this.version = 2.0
this.type = 'Document'
this.icon = 'plaintext.svg'
this.category = 'Document Loaders'
@@ -45,12 +47,25 @@ class PlainText_DocumentLoaders implements INode {
additionalParams: true
}
]
this.outputs = [
{
label: 'Document',
name: 'document',
baseClasses: this.baseClasses
},
{
label: 'Text',
name: 'text',
baseClasses: ['string', 'json']
}
]
}
async init(nodeData: INodeData): Promise<any> {
const textSplitter = nodeData.inputs?.textSplitter as TextSplitter
const text = nodeData.inputs?.text as string
const metadata = nodeData.inputs?.metadata
const output = nodeData.outputs?.output as string
let alldocs: Document<Record<string, any>>[] = []
@@ -65,9 +80,9 @@ class PlainText_DocumentLoaders implements INode {
)
}
let finaldocs: Document<Record<string, any>>[] = []
if (metadata) {
const parsedMetadata = typeof metadata === 'object' ? metadata : JSON.parse(metadata)
let finaldocs: Document<Record<string, any>>[] = []
for (const doc of alldocs) {
const newdoc = {
...doc,
@@ -78,10 +93,19 @@ class PlainText_DocumentLoaders implements INode {
}
finaldocs.push(newdoc)
}
return finaldocs
} else {
finaldocs = alldocs
}
return alldocs
if (output === 'document') {
return finaldocs
} else {
let finaltext = ''
for (const doc of finaldocs) {
finaltext += `${doc.pageContent}\n`
}
return handleEscapeCharacters(finaltext, false)
}
}
}
@@ -0,0 +1,241 @@
import { ICommonObject, INode, INodeData, INodeParams } from '../../../src/Interface'
import { S3Loader } from 'langchain/document_loaders/web/s3'
import { UnstructuredLoader } from 'langchain/document_loaders/fs/unstructured'
import { getCredentialData, getCredentialParam } from '../../../src/utils'
import { S3Client, GetObjectCommand, S3ClientConfig } from '@aws-sdk/client-s3'
import { Readable } from 'node:stream'
import * as fsDefault from 'node:fs'
import * as path from 'node:path'
import * as os from 'node:os'
type S3Config = S3ClientConfig & {
/** @deprecated Use the credentials object instead */
accessKeyId?: string
/** @deprecated Use the credentials object instead */
secretAccessKey?: string
}
class S3_DocumentLoaders implements INode {
label: string
name: string
version: number
description: string
type: string
icon: string
category: string
baseClasses: string[]
credential: INodeParams
inputs?: INodeParams[]
constructor() {
this.label = 'S3'
this.name = 'S3'
this.version = 1.0
this.type = 'Document'
this.icon = 's3.svg'
this.category = 'Document Loaders'
this.description = 'Load Data from S3 Buckets'
this.baseClasses = [this.type]
this.credential = {
label: 'AWS Credential',
name: 'credential',
type: 'credential',
credentialNames: ['awsApi']
}
this.inputs = [
{
label: 'Bucket',
name: 'bucketName',
type: 'string'
},
{
label: 'Object Key',
name: 'keyName',
type: 'string',
description: 'The object key (or key name) that uniquely identifies object in an Amazon S3 bucket',
placeholder: 'AI-Paper.pdf'
},
{
label: 'Region',
name: 'region',
type: 'options',
options: [
{ label: 'af-south-1', name: 'af-south-1' },
{ label: 'ap-east-1', name: 'ap-east-1' },
{ label: 'ap-northeast-1', name: 'ap-northeast-1' },
{ label: 'ap-northeast-2', name: 'ap-northeast-2' },
{ label: 'ap-northeast-3', name: 'ap-northeast-3' },
{ label: 'ap-south-1', name: 'ap-south-1' },
{ label: 'ap-south-2', name: 'ap-south-2' },
{ label: 'ap-southeast-1', name: 'ap-southeast-1' },
{ label: 'ap-southeast-2', name: 'ap-southeast-2' },
{ label: 'ap-southeast-3', name: 'ap-southeast-3' },
{ label: 'ap-southeast-4', name: 'ap-southeast-4' },
{ label: 'ap-southeast-5', name: 'ap-southeast-5' },
{ label: 'ap-southeast-6', name: 'ap-southeast-6' },
{ label: 'ca-central-1', name: 'ca-central-1' },
{ label: 'ca-west-1', name: 'ca-west-1' },
{ label: 'cn-north-1', name: 'cn-north-1' },
{ label: 'cn-northwest-1', name: 'cn-northwest-1' },
{ label: 'eu-central-1', name: 'eu-central-1' },
{ label: 'eu-central-2', name: 'eu-central-2' },
{ label: 'eu-north-1', name: 'eu-north-1' },
{ label: 'eu-south-1', name: 'eu-south-1' },
{ label: 'eu-south-2', name: 'eu-south-2' },
{ label: 'eu-west-1', name: 'eu-west-1' },
{ label: 'eu-west-2', name: 'eu-west-2' },
{ label: 'eu-west-3', name: 'eu-west-3' },
{ label: 'il-central-1', name: 'il-central-1' },
{ label: 'me-central-1', name: 'me-central-1' },
{ label: 'me-south-1', name: 'me-south-1' },
{ label: 'sa-east-1', name: 'sa-east-1' },
{ label: 'us-east-1', name: 'us-east-1' },
{ label: 'us-east-2', name: 'us-east-2' },
{ label: 'us-gov-east-1', name: 'us-gov-east-1' },
{ label: 'us-gov-west-1', name: 'us-gov-west-1' },
{ label: 'us-west-1', name: 'us-west-1' },
{ label: 'us-west-2', name: 'us-west-2' }
],
default: 'us-east-1'
},
{
label: 'Unstructured API URL',
name: 'unstructuredAPIUrl',
description:
'Your Unstructured.io URL. Read <a target="_blank" href="https://unstructured-io.github.io/unstructured/introduction.html#getting-started">more</a> on how to get started',
type: 'string',
default: 'http://localhost:8000/general/v0/general'
},
{
label: 'Unstructured API KEY',
name: 'unstructuredAPIKey',
type: 'password',
optional: true
},
{
label: 'NarrativeText Only',
name: 'narrativeTextOnly',
description:
'Only load documents with NarrativeText metadata from Unstructured. See how Unstructured partition data <a target="_blank" href="https://unstructured-io.github.io/unstructured/bricks/partition.html#">here</a>',
default: true,
type: 'boolean',
optional: true,
additionalParams: true
},
{
label: 'Metadata',
name: 'metadata',
type: 'json',
optional: true,
additionalParams: true
}
]
}
async init(nodeData: INodeData, _: string, options: ICommonObject): Promise<any> {
const bucketName = nodeData.inputs?.bucketName as string
const keyName = nodeData.inputs?.keyName as string
const region = nodeData.inputs?.region as string
const unstructuredAPIUrl = nodeData.inputs?.unstructuredAPIUrl as string
const unstructuredAPIKey = nodeData.inputs?.unstructuredAPIKey as string
const metadata = nodeData.inputs?.metadata
const narrativeTextOnly = nodeData.inputs?.narrativeTextOnly as boolean
const credentialData = await getCredentialData(nodeData.credential ?? '', options)
const accessKeyId = getCredentialParam('awsKey', credentialData, nodeData)
const secretAccessKey = getCredentialParam('awsSecret', credentialData, nodeData)
const loader = new S3Loader({
bucket: bucketName,
key: keyName,
s3Config: {
region,
credentials: {
accessKeyId,
secretAccessKey
}
},
unstructuredAPIURL: unstructuredAPIUrl,
unstructuredAPIKey: unstructuredAPIKey
})
const s3Config: S3Config & {
accessKeyId?: string
secretAccessKey?: string
} = {
accessKeyId,
secretAccessKey
}
loader.load = async () => {
const tempDir = fsDefault.mkdtempSync(path.join(os.tmpdir(), 's3fileloader-'))
const filePath = path.join(tempDir, keyName)
try {
const s3Client = new S3Client(s3Config)
const getObjectCommand = new GetObjectCommand({
Bucket: bucketName,
Key: keyName
})
const response = await s3Client.send(getObjectCommand)
const objectData = await new Promise<Buffer>((resolve, reject) => {
const chunks: Buffer[] = []
if (response.Body instanceof Readable) {
response.Body.on('data', (chunk: Buffer) => chunks.push(chunk))
response.Body.on('end', () => resolve(Buffer.concat(chunks)))
response.Body.on('error', reject)
} else {
reject(new Error('Response body is not a readable stream.'))
}
})
fsDefault.mkdirSync(path.dirname(filePath), { recursive: true })
fsDefault.writeFileSync(filePath, objectData)
} catch (e: any) {
throw new Error(`Failed to download file ${keyName} from S3 bucket ${bucketName}: ${e.message}`)
}
try {
const options = {
apiUrl: unstructuredAPIUrl,
apiKey: unstructuredAPIKey
}
const unstructuredLoader = new UnstructuredLoader(filePath, options)
const docs = await unstructuredLoader.load()
fsDefault.rmdirSync(path.dirname(filePath), { recursive: true })
return docs
} catch {
fsDefault.rmdirSync(path.dirname(filePath), { recursive: true })
throw new Error(`Failed to load file ${filePath} using unstructured loader.`)
}
}
const docs = await loader.load()
if (metadata) {
const parsedMetadata = typeof metadata === 'object' ? metadata : JSON.parse(metadata)
const finaldocs = docs.map((doc) => {
return {
...doc,
metadata: {
...doc.metadata,
...parsedMetadata
}
}
})
return narrativeTextOnly ? finaldocs.filter((doc) => doc.metadata.category === 'NarrativeText') : finaldocs
}
return narrativeTextOnly ? docs.filter((doc) => doc.metadata.category === 'NarrativeText') : docs
}
}
module.exports = { nodeClass: S3_DocumentLoaders }
@@ -0,0 +1 @@
<svg height="2500" width="2500" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 80 80"><linearGradient id="a" x1="0%" y1="100%" y2="0%"><stop offset="0" stop-color="#1b660f"/><stop offset="1" stop-color="#6cae3e"/></linearGradient><g fill="none" fill-rule="evenodd"><path d="M0 0h80v80H0z" fill="url(#a)"/><path d="M60.836 42.893l.384-2.704c3.54 2.12 3.587 2.997 3.586 3.02-.006.006-.61.51-3.97-.316zm-1.943-.54C52.773 40.5 44.25 36.59 40.8 34.96c0-.014.004-.027.004-.041a2.406 2.406 0 0 0-2.404-2.403c-1.324 0-2.402 1.078-2.402 2.403s1.078 2.403 2.402 2.403c.582 0 1.11-.217 1.527-.562 4.058 1.92 12.515 5.774 18.68 7.594L56.17 61.56a.955.955 0 0 0-.01.14c0 1.516-6.707 4.299-17.666 4.299-11.075 0-17.853-2.783-17.853-4.298 0-.046-.003-.091-.01-.136l-5.093-37.207c4.409 3.035 13.892 4.64 22.962 4.64 9.056 0 18.523-1.6 22.94-4.625zM15 20.478C15.072 19.162 22.634 14 38.5 14c15.864 0 23.427 5.16 23.5 6.478v.449C61.13 23.877 51.33 27 38.5 27c-12.852 0-22.657-3.132-23.5-6.087zm49 .022c0-3.465-9.934-8.5-25.5-8.5S13 17.035 13 20.5l.094.754 5.548 40.524C18.775 66.31 30.86 68 38.494 68c9.472 0 19.535-2.178 19.665-6.22l2.396-16.896c1.333.319 2.43.482 3.31.482 1.184 0 1.984-.29 2.469-.867a1.95 1.95 0 0 0 .436-1.66c-.26-1.383-1.902-2.875-5.248-4.784l2.376-16.762z" fill="#fff"/></g></svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

@@ -1,6 +1,8 @@
import { INode, INodeData, INodeParams } from '../../../src/Interface'
import { INode, INodeData, INodeOutputsValue, INodeParams } from '../../../src/Interface'
import { TextSplitter } from 'langchain/text_splitter'
import { TextLoader } from 'langchain/document_loaders/fs/text'
import { Document } from 'langchain/document'
import { handleEscapeCharacters } from '../../../src'
class Text_DocumentLoaders implements INode {
label: string
@@ -12,11 +14,12 @@ class Text_DocumentLoaders implements INode {
category: string
baseClasses: string[]
inputs: INodeParams[]
outputs: INodeOutputsValue[]
constructor() {
this.label = 'Text File'
this.name = 'textFile'
this.version = 1.0
this.version = 2.0
this.type = 'Document'
this.icon = 'textFile.svg'
this.category = 'Document Loaders'
@@ -43,12 +46,25 @@ class Text_DocumentLoaders implements INode {
additionalParams: true
}
]
this.outputs = [
{
label: 'Document',
name: 'document',
baseClasses: this.baseClasses
},
{
label: 'Text',
name: 'text',
baseClasses: ['string', 'json']
}
]
}
async init(nodeData: INodeData): Promise<any> {
const textSplitter = nodeData.inputs?.textSplitter as TextSplitter
const txtFileBase64 = nodeData.inputs?.txtFile as string
const metadata = nodeData.inputs?.metadata
const output = nodeData.outputs?.output as string
let alldocs = []
let files: string[] = []
@@ -75,9 +91,9 @@ class Text_DocumentLoaders implements INode {
}
}
let finaldocs: Document<Record<string, any>>[] = []
if (metadata) {
const parsedMetadata = typeof metadata === 'object' ? metadata : JSON.parse(metadata)
let finaldocs = []
for (const doc of alldocs) {
const newdoc = {
...doc,
@@ -88,9 +104,19 @@ class Text_DocumentLoaders implements INode {
}
finaldocs.push(newdoc)
}
return finaldocs
} else {
finaldocs = alldocs
}
if (output === 'document') {
return finaldocs
} else {
let finaltext = ''
for (const doc of finaldocs) {
finaltext += `${doc.pageContent}\n`
}
return handleEscapeCharacters(finaltext, false)
}
return alldocs
}
}
@@ -0,0 +1,162 @@
import { ICommonObject, INode, INodeData, INodeParams } from '../../../src/Interface'
import { UnstructuredLoader, UnstructuredLoaderOptions } from 'langchain/document_loaders/fs/unstructured'
import { getCredentialData, getCredentialParam } from '../../../src/utils'
class UnstructuredFile_DocumentLoaders implements INode {
label: string
name: string
version: number
description: string
type: string
icon: string
category: string
baseClasses: string[]
credential: INodeParams
inputs: INodeParams[]
constructor() {
this.label = 'Unstructured File Loader'
this.name = 'unstructuredFileLoader'
this.version = 1.0
this.type = 'Document'
this.icon = 'unstructured.png'
this.category = 'Document Loaders'
this.description = 'Use Unstructured.io to load data from a file path'
this.baseClasses = [this.type]
this.credential = {
label: 'Connect Credential',
name: 'credential',
type: 'credential',
credentialNames: ['unstructuredApi'],
optional: true
}
this.inputs = [
{
label: 'File Path',
name: 'filePath',
type: 'string',
placeholder: ''
},
{
label: 'Unstructured API URL',
name: 'unstructuredAPIUrl',
description:
'Unstructured API URL. Read <a target="_blank" href="https://unstructured-io.github.io/unstructured/introduction.html#getting-started">more</a> on how to get started',
type: 'string',
default: 'http://localhost:8000/general/v0/general'
},
{
label: 'Element Type',
name: 'elementType',
description:
'Unstructured partition document into different types, select the types to return. If not selected, all types will be returned',
type: 'multiOptions',
options: [
{
label: 'FigureCaption',
name: 'FigureCaption'
},
{
label: 'NarrativeText',
name: 'NarrativeText'
},
{
label: 'ListItem',
name: 'ListItem'
},
{
label: 'Title',
name: 'Title'
},
{
label: 'Address',
name: 'Address'
},
{
label: 'Table',
name: 'Table'
},
{
label: 'PageBreak',
name: 'PageBreak'
},
{
label: 'Header',
name: 'Header'
},
{
label: 'Footer',
name: 'Footer'
},
{
label: 'UncategorizedText',
name: 'UncategorizedText'
},
{
label: 'Image',
name: 'Image'
},
{
label: 'Formula',
name: 'Formula'
}
],
default: [],
optional: true,
additionalParams: true
},
{
label: 'Metadata',
name: 'metadata',
type: 'json',
optional: true,
additionalParams: true
}
]
}
async init(nodeData: INodeData, _: string, options: ICommonObject): Promise<any> {
const filePath = nodeData.inputs?.filePath as string
const unstructuredAPIUrl = nodeData.inputs?.unstructuredAPIUrl as string
const elementType = nodeData.inputs?.elementType as string
const metadata = nodeData.inputs?.metadata
const obj: UnstructuredLoaderOptions = { apiUrl: unstructuredAPIUrl }
const credentialData = await getCredentialData(nodeData.credential ?? '', options)
const unstructuredAPIKey = getCredentialParam('unstructuredAPIKey', credentialData, nodeData)
if (unstructuredAPIKey) obj.apiKey = unstructuredAPIKey
const loader = new UnstructuredLoader(filePath, obj)
const docs = await loader.load()
let elementTypes: string[] = []
if (elementType) {
try {
elementTypes = JSON.parse(elementType)
} catch (e) {
elementTypes = []
}
}
if (metadata) {
const parsedMetadata = typeof metadata === 'object' ? metadata : JSON.parse(metadata)
let finaldocs = []
for (const doc of docs) {
const newdoc = {
...doc,
metadata: {
...doc.metadata,
...parsedMetadata
}
}
finaldocs.push(newdoc)
}
return elementTypes.length ? finaldocs.filter((doc) => elementTypes.includes(doc.metadata.category)) : finaldocs
}
return elementTypes.length ? docs.filter((doc) => elementTypes.includes(doc.metadata.category)) : docs
}
}
module.exports = { nodeClass: UnstructuredFile_DocumentLoaders }
@@ -0,0 +1,162 @@
import { ICommonObject, INode, INodeData, INodeParams } from '../../../src/Interface'
import { UnstructuredDirectoryLoader, UnstructuredLoaderOptions } from 'langchain/document_loaders/fs/unstructured'
import { getCredentialData, getCredentialParam } from '../../../src/utils'
class UnstructuredFolder_DocumentLoaders implements INode {
label: string
name: string
version: number
description: string
type: string
icon: string
category: string
baseClasses: string[]
credential: INodeParams
inputs: INodeParams[]
constructor() {
this.label = 'Unstructured Folder Loader'
this.name = 'unstructuredFolderLoader'
this.version = 1.0
this.type = 'Document'
this.icon = 'unstructured.png'
this.category = 'Document Loaders'
this.description = 'Use Unstructured.io to load data from a folder'
this.baseClasses = [this.type]
this.credential = {
label: 'Connect Credential',
name: 'credential',
type: 'credential',
credentialNames: ['unstructuredApi'],
optional: true
}
this.inputs = [
{
label: 'Folder Path',
name: 'folderPath',
type: 'string',
placeholder: ''
},
{
label: 'Unstructured API URL',
name: 'unstructuredAPIUrl',
description:
'Unstructured API URL. Read <a target="_blank" href="https://unstructured-io.github.io/unstructured/introduction.html#getting-started">more</a> on how to get started',
type: 'string',
default: 'http://localhost:8000/general/v0/general'
},
{
label: 'Element Type',
name: 'elementType',
description:
'Unstructured partition document into different types, select the types to return. If not selected, all types will be returned',
type: 'multiOptions',
options: [
{
label: 'FigureCaption',
name: 'FigureCaption'
},
{
label: 'NarrativeText',
name: 'NarrativeText'
},
{
label: 'ListItem',
name: 'ListItem'
},
{
label: 'Title',
name: 'Title'
},
{
label: 'Address',
name: 'Address'
},
{
label: 'Table',
name: 'Table'
},
{
label: 'PageBreak',
name: 'PageBreak'
},
{
label: 'Header',
name: 'Header'
},
{
label: 'Footer',
name: 'Footer'
},
{
label: 'UncategorizedText',
name: 'UncategorizedText'
},
{
label: 'Image',
name: 'Image'
},
{
label: 'Formula',
name: 'Formula'
}
],
default: [],
optional: true,
additionalParams: true
},
{
label: 'Metadata',
name: 'metadata',
type: 'json',
optional: true,
additionalParams: true
}
]
}
async init(nodeData: INodeData, _: string, options: ICommonObject): Promise<any> {
const folderPath = nodeData.inputs?.folderPath as string
const unstructuredAPIUrl = nodeData.inputs?.unstructuredAPIUrl as string
const metadata = nodeData.inputs?.metadata
const elementType = nodeData.inputs?.elementType as string
const obj: UnstructuredLoaderOptions = { apiUrl: unstructuredAPIUrl }
const credentialData = await getCredentialData(nodeData.credential ?? '', options)
const unstructuredAPIKey = getCredentialParam('unstructuredAPIKey', credentialData, nodeData)
if (unstructuredAPIKey) obj.apiKey = unstructuredAPIKey
const loader = new UnstructuredDirectoryLoader(folderPath, obj)
const docs = await loader.load()
let elementTypes: string[] = []
if (elementType) {
try {
elementTypes = JSON.parse(elementType)
} catch (e) {
elementTypes = []
}
}
if (metadata) {
const parsedMetadata = typeof metadata === 'object' ? metadata : JSON.parse(metadata)
let finaldocs = []
for (const doc of docs) {
const newdoc = {
...doc,
metadata: {
...doc.metadata,
...parsedMetadata
}
}
finaldocs.push(newdoc)
}
return elementTypes.length ? finaldocs.filter((doc) => elementTypes.includes(doc.metadata.category)) : finaldocs
}
return elementTypes.length ? docs.filter((doc) => elementTypes.includes(doc.metadata.category)) : docs
}
}
module.exports = { nodeClass: UnstructuredFolder_DocumentLoaders }
Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

@@ -0,0 +1,152 @@
import { ICommonObject, INode, INodeData, INodeParams } from '../../../src/Interface'
import { getBaseClasses, getCredentialData, getCredentialParam } from '../../../src/utils'
import { BedrockEmbeddings, BedrockEmbeddingsParams } from 'langchain/embeddings/bedrock'
import { BedrockRuntimeClient, InvokeModelCommand } from '@aws-sdk/client-bedrock-runtime'
class AWSBedrockEmbedding_Embeddings implements INode {
label: string
name: string
version: number
type: string
icon: string
category: string
description: string
baseClasses: string[]
credential: INodeParams
inputs: INodeParams[]
constructor() {
this.label = 'AWS Bedrock Embeddings'
this.name = 'AWSBedrockEmbeddings'
this.version = 1.0
this.type = 'AWSBedrockEmbeddings'
this.icon = 'awsBedrock.png'
this.category = 'Embeddings'
this.description = 'AWSBedrock embedding models to generate embeddings for a given text'
this.baseClasses = [this.type, ...getBaseClasses(BedrockEmbeddings)]
this.credential = {
label: 'AWS Credential',
name: 'credential',
type: 'credential',
credentialNames: ['awsApi'],
optional: true
}
this.inputs = [
{
label: 'Region',
name: 'region',
type: 'options',
options: [
{ label: 'af-south-1', name: 'af-south-1' },
{ label: 'ap-east-1', name: 'ap-east-1' },
{ label: 'ap-northeast-1', name: 'ap-northeast-1' },
{ label: 'ap-northeast-2', name: 'ap-northeast-2' },
{ label: 'ap-northeast-3', name: 'ap-northeast-3' },
{ label: 'ap-south-1', name: 'ap-south-1' },
{ label: 'ap-south-2', name: 'ap-south-2' },
{ label: 'ap-southeast-1', name: 'ap-southeast-1' },
{ label: 'ap-southeast-2', name: 'ap-southeast-2' },
{ label: 'ap-southeast-3', name: 'ap-southeast-3' },
{ label: 'ap-southeast-4', name: 'ap-southeast-4' },
{ label: 'ap-southeast-5', name: 'ap-southeast-5' },
{ label: 'ap-southeast-6', name: 'ap-southeast-6' },
{ label: 'ca-central-1', name: 'ca-central-1' },
{ label: 'ca-west-1', name: 'ca-west-1' },
{ label: 'cn-north-1', name: 'cn-north-1' },
{ label: 'cn-northwest-1', name: 'cn-northwest-1' },
{ label: 'eu-central-1', name: 'eu-central-1' },
{ label: 'eu-central-2', name: 'eu-central-2' },
{ label: 'eu-north-1', name: 'eu-north-1' },
{ label: 'eu-south-1', name: 'eu-south-1' },
{ label: 'eu-south-2', name: 'eu-south-2' },
{ label: 'eu-west-1', name: 'eu-west-1' },
{ label: 'eu-west-2', name: 'eu-west-2' },
{ label: 'eu-west-3', name: 'eu-west-3' },
{ label: 'il-central-1', name: 'il-central-1' },
{ label: 'me-central-1', name: 'me-central-1' },
{ label: 'me-south-1', name: 'me-south-1' },
{ label: 'sa-east-1', name: 'sa-east-1' },
{ label: 'us-east-1', name: 'us-east-1' },
{ label: 'us-east-2', name: 'us-east-2' },
{ label: 'us-gov-east-1', name: 'us-gov-east-1' },
{ label: 'us-gov-west-1', name: 'us-gov-west-1' },
{ label: 'us-west-1', name: 'us-west-1' },
{ label: 'us-west-2', name: 'us-west-2' }
],
default: 'us-east-1'
},
{
label: 'Model Name',
name: 'model',
type: 'options',
options: [{ label: 'amazon.titan-embed-text-v1', name: 'amazon.titan-embed-text-v1' }],
default: 'amazon.titan-embed-text-v1'
}
]
}
async init(nodeData: INodeData, _: string, options: ICommonObject): Promise<any> {
const iRegion = nodeData.inputs?.region as string
const iModel = nodeData.inputs?.model as string
const obj: BedrockEmbeddingsParams = {
model: iModel,
region: iRegion
}
const credentialData = await getCredentialData(nodeData.credential ?? '', options)
if (credentialData && Object.keys(credentialData).length !== 0) {
const credentialApiKey = getCredentialParam('awsKey', credentialData, nodeData)
const credentialApiSecret = getCredentialParam('awsSecret', credentialData, nodeData)
const credentialApiSession = getCredentialParam('awsSession', credentialData, nodeData)
obj.credentials = {
accessKeyId: credentialApiKey,
secretAccessKey: credentialApiSecret,
sessionToken: credentialApiSession
}
}
const client = new BedrockRuntimeClient({
region: obj.region,
credentials: obj.credentials
})
const model = new BedrockEmbeddings(obj)
// Avoid Illegal Invocation
model.embedQuery = async (document: string): Promise<number[]> => {
return await embedText(document, client, iModel)
}
model.embedDocuments = async (documents: string[]): Promise<number[][]> => {
return Promise.all(documents.map((document) => embedText(document, client, iModel)))
}
return model
}
}
const embedText = async (text: string, client: BedrockRuntimeClient, model: string): Promise<number[]> => {
// replace newlines, which can negatively affect performance.
const cleanedText = text.replace(/\n/g, ' ')
const res = await client.send(
new InvokeModelCommand({
modelId: model,
body: JSON.stringify({
inputText: cleanedText
}),
contentType: 'application/json',
accept: 'application/json'
})
)
try {
const body = new TextDecoder().decode(res.body)
return JSON.parse(body).embedding
} catch (e) {
throw new Error('An invalid response was returned by Bedrock.')
}
}
module.exports = { nodeClass: AWSBedrockEmbedding_Embeddings }
Binary file not shown.

After

Width:  |  Height:  |  Size: 61 KiB

@@ -0,0 +1,95 @@
import { INode, INodeData, INodeParams } from '../../../src/Interface'
import { getBaseClasses } from '../../../src/utils'
import { OllamaEmbeddings } from 'langchain/embeddings/ollama'
import { OllamaInput } from 'langchain/dist/util/ollama'
class OllamaEmbedding_Embeddings implements INode {
label: string
name: string
version: number
type: string
icon: string
category: string
description: string
baseClasses: string[]
credential: INodeParams
inputs: INodeParams[]
constructor() {
this.label = 'Ollama Embeddings'
this.name = 'ollamaEmbedding'
this.version = 1.0
this.type = 'OllamaEmbeddings'
this.icon = 'ollama.png'
this.category = 'Embeddings'
this.description = 'Generate embeddings for a given text using open source model on Ollama'
this.baseClasses = [this.type, ...getBaseClasses(OllamaEmbeddings)]
this.inputs = [
{
label: 'Base URL',
name: 'baseUrl',
type: 'string',
default: 'http://localhost:11434'
},
{
label: 'Model Name',
name: 'modelName',
type: 'string',
placeholder: 'llama2'
},
{
label: 'Number of GPU',
name: 'numGpu',
type: 'number',
description:
'The number of layers to send to the GPU(s). On macOS it defaults to 1 to enable metal support, 0 to disable. Refer to <a target="_blank" href="https://github.com/jmorganca/ollama/blob/main/docs/modelfile.md#valid-parameters-and-values">docs</a> for more details',
step: 1,
optional: true,
additionalParams: true
},
{
label: 'Number of Thread',
name: 'numThread',
type: 'number',
description:
'Sets the number of threads to use during computation. By default, Ollama will detect this for optimal performance. It is recommended to set this value to the number of physical CPU cores your system has (as opposed to the logical number of cores). Refer to <a target="_blank" href="https://github.com/jmorganca/ollama/blob/main/docs/modelfile.md#valid-parameters-and-values">docs</a> for more details',
step: 1,
optional: true,
additionalParams: true
},
{
label: 'Use MMap',
name: 'useMMap',
type: 'boolean',
optional: true,
additionalParams: true
}
]
}
async init(nodeData: INodeData): Promise<any> {
const modelName = nodeData.inputs?.modelName as string
const baseUrl = nodeData.inputs?.baseUrl as string
const numThread = nodeData.inputs?.numThread as string
const numGpu = nodeData.inputs?.numGpu as string
const useMMap = nodeData.inputs?.useMMap as boolean
const obj = {
model: modelName,
baseUrl,
requestOptions: {}
}
const requestOptions: OllamaInput = {}
if (numThread) requestOptions.numThread = parseFloat(numThread)
if (numGpu) requestOptions.numGpu = parseFloat(numGpu)
if (useMMap !== undefined) requestOptions.useMMap = useMMap
if (Object.keys(requestOptions).length) obj.requestOptions = requestOptions
const model = new OllamaEmbeddings(obj)
return model
}
}
module.exports = { nodeClass: OllamaEmbedding_Embeddings }
Binary file not shown.

After

Width:  |  Height:  |  Size: 7.3 KiB

@@ -2,6 +2,8 @@ import { ICommonObject, INode, INodeData, INodeParams } from '../../../src/Inter
import { getBaseClasses, getCredentialData, getCredentialParam } from '../../../src/utils'
import { Bedrock } from 'langchain/llms/bedrock'
import { BaseBedrockInput } from 'langchain/dist/util/bedrock'
import { BaseCache } from 'langchain/schema'
import { BaseLLMParams } from 'langchain/llms/base'
/**
* I had to run the following to build the component
@@ -39,6 +41,12 @@ class AWSBedrock_LLMs implements INode {
optional: true
}
this.inputs = [
{
label: 'Cache',
name: 'cache',
type: 'BaseCache',
optional: true
},
{
label: 'Region',
name: 'region',
@@ -80,8 +88,7 @@ class AWSBedrock_LLMs implements INode {
{ label: 'us-west-1', name: 'us-west-1' },
{ label: 'us-west-2', name: 'us-west-2' }
],
default: 'us-east-1',
optional: false
default: 'us-east-1'
},
{
label: 'Model Name',
@@ -90,17 +97,12 @@ class AWSBedrock_LLMs implements INode {
options: [
{ label: 'amazon.titan-tg1-large', name: 'amazon.titan-tg1-large' },
{ label: 'amazon.titan-e1t-medium', name: 'amazon.titan-e1t-medium' },
{ label: 'stability.stable-diffusion-xl', name: 'stability.stable-diffusion-xl' },
{ label: 'cohere.command-text-v14', name: 'cohere.command-text-v14' },
{ label: 'ai21.j2-grande-instruct', name: 'ai21.j2-grande-instruct' },
{ label: 'ai21.j2-jumbo-instruct', name: 'ai21.j2-jumbo-instruct' },
{ label: 'ai21.j2-mid', name: 'ai21.j2-mid' },
{ label: 'ai21.j2-ultra', name: 'ai21.j2-ultra' },
{ label: 'anthropic.claude-instant-v1', name: 'anthropic.claude-instant-v1' },
{ label: 'anthropic.claude-v1', name: 'anthropic.claude-v1' },
{ label: 'anthropic.claude-v2', name: 'anthropic.claude-v2' }
],
default: 'anthropic.claude-v2',
optional: false
{ label: 'ai21.j2-ultra', name: 'ai21.j2-ultra' }
]
},
{
label: 'Temperature',
@@ -109,8 +111,7 @@ class AWSBedrock_LLMs implements INode {
step: 0.1,
description: 'Temperature parameter may not apply to certain model. Please check available model parameters',
optional: true,
default: 0.7,
additionalParams: false
default: 0.7
},
{
label: 'Max Tokens to Sample',
@@ -118,9 +119,8 @@ class AWSBedrock_LLMs implements INode {
type: 'number',
step: 10,
description: 'Max Tokens parameter may not apply to certain model. Please check available model parameters',
optional: false,
default: 200,
additionalParams: false
optional: true,
default: 200
}
]
}
@@ -130,8 +130,8 @@ class AWSBedrock_LLMs implements INode {
const iModel = nodeData.inputs?.model as string
const iTemperature = nodeData.inputs?.temperature as string
const iMax_tokens_to_sample = nodeData.inputs?.max_tokens_to_sample as string
const obj: Partial<BaseBedrockInput> = {
const cache = nodeData.inputs?.cache as BaseCache
const obj: Partial<BaseBedrockInput> & BaseLLMParams = {
model: iModel,
region: iRegion,
temperature: parseFloat(iTemperature),
@@ -157,6 +157,7 @@ class AWSBedrock_LLMs implements INode {
sessionToken: credentialApiSession
}
}
if (cache) obj.cache = cache
const amazonBedrock = new Bedrock(obj)
return amazonBedrock
@@ -1,7 +1,8 @@
import { ICommonObject, INode, INodeData, INodeParams } from '../../../src/Interface'
import { getBaseClasses, getCredentialData, getCredentialParam } from '../../../src/utils'
import { AzureOpenAIInput, OpenAI, OpenAIInput } from 'langchain/llms/openai'
import { BaseCache } from 'langchain/schema'
import { BaseLLMParams } from 'langchain/llms/base'
class AzureOpenAI_LLMs implements INode {
label: string
name: string
@@ -17,7 +18,7 @@ class AzureOpenAI_LLMs implements INode {
constructor() {
this.label = 'Azure OpenAI'
this.name = 'azureOpenAI'
this.version = 1.0
this.version = 2.0
this.type = 'AzureOpenAI'
this.icon = 'Azure.svg'
this.category = 'LLMs'
@@ -30,6 +31,12 @@ class AzureOpenAI_LLMs implements INode {
credentialNames: ['azureOpenAIApi']
}
this.inputs = [
{
label: 'Cache',
name: 'cache',
type: 'BaseCache',
optional: true
},
{
label: 'Model Name',
name: 'modelName',
@@ -163,7 +170,9 @@ class AzureOpenAI_LLMs implements INode {
const azureOpenAIApiDeploymentName = getCredentialParam('azureOpenAIApiDeploymentName', credentialData, nodeData)
const azureOpenAIApiVersion = getCredentialParam('azureOpenAIApiVersion', credentialData, nodeData)
const obj: Partial<AzureOpenAIInput> & Partial<OpenAIInput> = {
const cache = nodeData.inputs?.cache as BaseCache
const obj: Partial<AzureOpenAIInput> & BaseLLMParams & Partial<OpenAIInput> = {
temperature: parseFloat(temperature),
modelName,
azureOpenAIApiKey,
@@ -179,6 +188,7 @@ class AzureOpenAI_LLMs implements INode {
if (presencePenalty) obj.presencePenalty = parseFloat(presencePenalty)
if (timeout) obj.timeout = parseInt(timeout, 10)
if (bestOf) obj.bestOf = parseInt(bestOf, 10)
if (cache) obj.cache = cache
const model = new OpenAI(obj)
return model
@@ -1,6 +1,8 @@
import { INode, INodeData, INodeParams } from '../../../src/Interface'
import { getBaseClasses } from '../../../src/utils'
import { NIBittensorLLM, BittensorInput } from 'langchain/experimental/llms/bittensor'
import { BaseCache } from 'langchain/schema'
import { BaseLLMParams } from 'langchain/llms/base'
class Bittensor_LLMs implements INode {
label: string
@@ -16,13 +18,19 @@ class Bittensor_LLMs implements INode {
constructor() {
this.label = 'NIBittensorLLM'
this.name = 'NIBittensorLLM'
this.version = 1.0
this.version = 2.0
this.type = 'Bittensor'
this.icon = 'logo.png'
this.category = 'LLMs'
this.description = 'Wrapper around Bittensor subnet 1 large language models'
this.baseClasses = [this.type, ...getBaseClasses(NIBittensorLLM)]
this.inputs = [
{
label: 'Cache',
name: 'cache',
type: 'BaseCache',
optional: true
},
{
label: 'System prompt',
name: 'system_prompt',
@@ -44,10 +52,13 @@ class Bittensor_LLMs implements INode {
async init(nodeData: INodeData, _: string): Promise<any> {
const system_prompt = nodeData.inputs?.system_prompt as string
const topResponses = Number(nodeData.inputs?.topResponses as number)
const obj: Partial<BittensorInput> = {
const cache = nodeData.inputs?.cache as BaseCache
const obj: Partial<BittensorInput> & BaseLLMParams = {
systemPrompt: system_prompt,
topResponses: topResponses
}
if (cache) obj.cache = cache
const model = new NIBittensorLLM(obj)
return model
@@ -1,6 +1,7 @@
import { ICommonObject, INode, INodeData, INodeParams } from '../../../src/Interface'
import { getBaseClasses, getCredentialData, getCredentialParam } from '../../../src/utils'
import { Cohere, CohereInput } from './core'
import { BaseCache } from 'langchain/schema'
class Cohere_LLMs implements INode {
label: string
@@ -17,7 +18,7 @@ class Cohere_LLMs implements INode {
constructor() {
this.label = 'Cohere'
this.name = 'cohere'
this.version = 1.0
this.version = 2.0
this.type = 'Cohere'
this.icon = 'cohere.png'
this.category = 'LLMs'
@@ -30,6 +31,12 @@ class Cohere_LLMs implements INode {
credentialNames: ['cohereApi']
}
this.inputs = [
{
label: 'Cache',
name: 'cache',
type: 'BaseCache',
optional: true
},
{
label: 'Model Name',
name: 'modelName',
@@ -85,7 +92,7 @@ class Cohere_LLMs implements INode {
const temperature = nodeData.inputs?.temperature as string
const modelName = nodeData.inputs?.modelName as string
const maxTokens = nodeData.inputs?.maxTokens as string
const cache = nodeData.inputs?.cache as BaseCache
const credentialData = await getCredentialData(nodeData.credential ?? '', options)
const cohereApiKey = getCredentialParam('cohereApiKey', credentialData, nodeData)
@@ -96,7 +103,7 @@ class Cohere_LLMs implements INode {
if (maxTokens) obj.maxTokens = parseInt(maxTokens, 10)
if (modelName) obj.model = modelName
if (temperature) obj.temperature = parseFloat(temperature)
if (cache) obj.cache = cache
const model = new Cohere(obj)
return model
}
@@ -1,7 +1,7 @@
import { ICommonObject, INode, INodeData, INodeParams } from '../../../src/Interface'
import { getBaseClasses, getCredentialData, getCredentialParam } from '../../../src/utils'
import { GooglePaLM, GooglePaLMTextInput } from 'langchain/llms/googlepalm'
import { BaseCache } from 'langchain/schema'
class GooglePaLM_LLMs implements INode {
label: string
name: string
@@ -17,7 +17,7 @@ class GooglePaLM_LLMs implements INode {
constructor() {
this.label = 'GooglePaLM'
this.name = 'GooglePaLM'
this.version = 1.0
this.version = 2.0
this.type = 'GooglePaLM'
this.icon = 'Google_PaLM_Logo.svg'
this.category = 'LLMs'
@@ -30,6 +30,12 @@ class GooglePaLM_LLMs implements INode {
credentialNames: ['googleMakerSuite']
}
this.inputs = [
{
label: 'Cache',
name: 'cache',
type: 'BaseCache',
optional: true
},
{
label: 'Model Name',
name: 'modelName',
@@ -126,6 +132,7 @@ class GooglePaLM_LLMs implements INode {
const topP = nodeData.inputs?.topP as string
const topK = nodeData.inputs?.topK as string
const stopSequencesObj = nodeData.inputs?.stopSequencesObj
const cache = nodeData.inputs?.cache as BaseCache
const credentialData = await getCredentialData(nodeData.credential ?? '', options)
const googleMakerSuiteKey = getCredentialParam('googleMakerSuiteKey', credentialData, nodeData)
@@ -139,6 +146,7 @@ class GooglePaLM_LLMs implements INode {
if (maxOutputTokens) obj.maxOutputTokens = parseInt(maxOutputTokens, 10)
if (topP) obj.topP = parseFloat(topP)
if (topK) obj.topK = parseFloat(topK)
if (cache) obj.cache = cache
let parsedStopSequences: any | undefined = undefined
if (stopSequencesObj) {
@@ -2,6 +2,7 @@ import { ICommonObject, INode, INodeData, INodeParams } from '../../../src/Inter
import { getBaseClasses, getCredentialData, getCredentialParam } from '../../../src/utils'
import { GoogleVertexAI, GoogleVertexAITextInput } from 'langchain/llms/googlevertexai'
import { GoogleAuthOptions } from 'google-auth-library'
import { BaseCache } from 'langchain/schema'
class GoogleVertexAI_LLMs implements INode {
label: string
@@ -18,7 +19,7 @@ class GoogleVertexAI_LLMs implements INode {
constructor() {
this.label = 'GoogleVertexAI'
this.name = 'googlevertexai'
this.version = 1.0
this.version = 2.0
this.type = 'GoogleVertexAI'
this.icon = 'vertexai.svg'
this.category = 'LLMs'
@@ -34,6 +35,12 @@ class GoogleVertexAI_LLMs implements INode {
'Google Vertex AI credential. If you are using a GCP service like Cloud Run, or if you have installed default credentials on your local machine, you do not need to set this credential.'
}
this.inputs = [
{
label: 'Cache',
name: 'cache',
type: 'BaseCache',
optional: true
},
{
label: 'Model Name',
name: 'modelName',
@@ -120,6 +127,7 @@ class GoogleVertexAI_LLMs implements INode {
const modelName = nodeData.inputs?.modelName as string
const maxOutputTokens = nodeData.inputs?.maxOutputTokens as string
const topP = nodeData.inputs?.topP as string
const cache = nodeData.inputs?.cache as BaseCache
const obj: Partial<GoogleVertexAITextInput> = {
temperature: parseFloat(temperature),
@@ -129,6 +137,7 @@ class GoogleVertexAI_LLMs implements INode {
if (maxOutputTokens) obj.maxOutputTokens = parseInt(maxOutputTokens, 10)
if (topP) obj.topP = parseFloat(topP)
if (cache) obj.cache = cache
const model = new GoogleVertexAI(obj)
return model
@@ -1,6 +1,7 @@
import { ICommonObject, INode, INodeData, INodeParams } from '../../../src/Interface'
import { getBaseClasses, getCredentialData, getCredentialParam } from '../../../src/utils'
import { HFInput, HuggingFaceInference } from './core'
import { BaseCache } from 'langchain/schema'
class HuggingFaceInference_LLMs implements INode {
label: string
@@ -17,7 +18,7 @@ class HuggingFaceInference_LLMs implements INode {
constructor() {
this.label = 'HuggingFace Inference'
this.name = 'huggingFaceInference_LLMs'
this.version = 1.0
this.version = 2.0
this.type = 'HuggingFaceInference'
this.icon = 'huggingface.png'
this.category = 'LLMs'
@@ -30,6 +31,12 @@ class HuggingFaceInference_LLMs implements INode {
credentialNames: ['huggingFaceApi']
}
this.inputs = [
{
label: 'Cache',
name: 'cache',
type: 'BaseCache',
optional: true
},
{
label: 'Model',
name: 'model',
@@ -106,6 +113,8 @@ class HuggingFaceInference_LLMs implements INode {
const credentialData = await getCredentialData(nodeData.credential ?? '', options)
const huggingFaceApiKey = getCredentialParam('huggingFaceApiKey', credentialData, nodeData)
const cache = nodeData.inputs?.cache as BaseCache
const obj: Partial<HFInput> = {
model,
apiKey: huggingFaceApiKey
@@ -119,6 +128,8 @@ class HuggingFaceInference_LLMs implements INode {
if (endpoint) obj.endpoint = endpoint
const huggingFace = new HuggingFaceInference(obj)
if (cache) huggingFace.cache = cache
return huggingFace
}
}
@@ -0,0 +1,241 @@
import { INode, INodeData, INodeParams } from '../../../src/Interface'
import { getBaseClasses } from '../../../src/utils'
import { Ollama } from 'langchain/llms/ollama'
import { BaseCache } from 'langchain/schema'
import { OllamaInput } from 'langchain/dist/util/ollama'
import { BaseLLMParams } from 'langchain/llms/base'
class Ollama_LLMs implements INode {
label: string
name: string
version: number
type: string
icon: string
category: string
description: string
baseClasses: string[]
credential: INodeParams
inputs: INodeParams[]
constructor() {
this.label = 'Ollama'
this.name = 'ollama'
this.version = 2.0
this.type = 'Ollama'
this.icon = 'ollama.png'
this.category = 'LLMs'
this.description = 'Wrapper around open source large language models on Ollama'
this.baseClasses = [this.type, ...getBaseClasses(Ollama)]
this.inputs = [
{
label: 'Cache',
name: 'cache',
type: 'BaseCache',
optional: true
},
{
label: 'Base URL',
name: 'baseUrl',
type: 'string',
default: 'http://localhost:11434'
},
{
label: 'Model Name',
name: 'modelName',
type: 'string',
placeholder: 'llama2'
},
{
label: 'Temperature',
name: 'temperature',
type: 'number',
description:
'The temperature of the model. Increasing the temperature will make the model answer more creatively. (Default: 0.8). Refer to <a target="_blank" href="https://github.com/jmorganca/ollama/blob/main/docs/modelfile.md#valid-parameters-and-values">docs</a> for more details',
step: 0.1,
default: 0.9,
optional: true
},
{
label: 'Top P',
name: 'topP',
type: 'number',
description:
'Works together with top-k. A higher value (e.g., 0.95) will lead to more diverse text, while a lower value (e.g., 0.5) will generate more focused and conservative text. (Default: 0.9). Refer to <a target="_blank" href="https://github.com/jmorganca/ollama/blob/main/docs/modelfile.md#valid-parameters-and-values">docs</a> for more details',
step: 0.1,
optional: true,
additionalParams: true
},
{
label: 'Top K',
name: 'topK',
type: 'number',
description:
'Reduces the probability of generating nonsense. A higher value (e.g. 100) will give more diverse answers, while a lower value (e.g. 10) will be more conservative. (Default: 40). Refer to <a target="_blank" href="https://github.com/jmorganca/ollama/blob/main/docs/modelfile.md#valid-parameters-and-values">docs</a> for more details',
step: 1,
optional: true,
additionalParams: true
},
{
label: 'Mirostat',
name: 'mirostat',
type: 'number',
description:
'Enable Mirostat sampling for controlling perplexity. (default: 0, 0 = disabled, 1 = Mirostat, 2 = Mirostat 2.0). Refer to <a target="_blank" href="https://github.com/jmorganca/ollama/blob/main/docs/modelfile.md#valid-parameters-and-values">docs</a> for more details',
step: 1,
optional: true,
additionalParams: true
},
{
label: 'Mirostat ETA',
name: 'mirostatEta',
type: 'number',
description:
'Influences how quickly the algorithm responds to feedback from the generated text. A lower learning rate will result in slower adjustments, while a higher learning rate will make the algorithm more responsive. (Default: 0.1) Refer to <a target="_blank" href="https://github.com/jmorganca/ollama/blob/main/docs/modelfile.md#valid-parameters-and-values">docs</a> for more details',
step: 0.1,
optional: true,
additionalParams: true
},
{
label: 'Mirostat TAU',
name: 'mirostatTau',
type: 'number',
description:
'Controls the balance between coherence and diversity of the output. A lower value will result in more focused and coherent text. (Default: 5.0) Refer to <a target="_blank" href="https://github.com/jmorganca/ollama/blob/main/docs/modelfile.md#valid-parameters-and-values">docs</a> for more details',
step: 0.1,
optional: true,
additionalParams: true
},
{
label: 'Context Window Size',
name: 'numCtx',
type: 'number',
description:
'Sets the size of the context window used to generate the next token. (Default: 2048) Refer to <a target="_blank" href="https://github.com/jmorganca/ollama/blob/main/docs/modelfile.md#valid-parameters-and-values">docs</a> for more details',
step: 1,
optional: true,
additionalParams: true
},
{
label: 'Number of GQA groups',
name: 'numGqa',
type: 'number',
description:
'The number of GQA groups in the transformer layer. Required for some models, for example it is 8 for llama2:70b. Refer to <a target="_blank" href="https://github.com/jmorganca/ollama/blob/main/docs/modelfile.md#valid-parameters-and-values">docs</a> for more details',
step: 1,
optional: true,
additionalParams: true
},
{
label: 'Number of GPU',
name: 'numGpu',
type: 'number',
description:
'The number of layers to send to the GPU(s). On macOS it defaults to 1 to enable metal support, 0 to disable. Refer to <a target="_blank" href="https://github.com/jmorganca/ollama/blob/main/docs/modelfile.md#valid-parameters-and-values">docs</a> for more details',
step: 1,
optional: true,
additionalParams: true
},
{
label: 'Number of Thread',
name: 'numThread',
type: 'number',
description:
'Sets the number of threads to use during computation. By default, Ollama will detect this for optimal performance. It is recommended to set this value to the number of physical CPU cores your system has (as opposed to the logical number of cores). Refer to <a target="_blank" href="https://github.com/jmorganca/ollama/blob/main/docs/modelfile.md#valid-parameters-and-values">docs</a> for more details',
step: 1,
optional: true,
additionalParams: true
},
{
label: 'Repeat Last N',
name: 'repeatLastN',
type: 'number',
description:
'Sets how far back for the model to look back to prevent repetition. (Default: 64, 0 = disabled, -1 = num_ctx). Refer to <a target="_blank" href="https://github.com/jmorganca/ollama/blob/main/docs/modelfile.md#valid-parameters-and-values">docs</a> for more details',
step: 1,
optional: true,
additionalParams: true
},
{
label: 'Repeat Penalty',
name: 'repeatPenalty',
type: 'number',
description:
'Sets how strongly to penalize repetitions. A higher value (e.g., 1.5) will penalize repetitions more strongly, while a lower value (e.g., 0.9) will be more lenient. (Default: 1.1). Refer to <a target="_blank" href="https://github.com/jmorganca/ollama/blob/main/docs/modelfile.md#valid-parameters-and-values">docs</a> for more details',
step: 0.1,
optional: true,
additionalParams: true
},
{
label: 'Stop Sequence',
name: 'stop',
type: 'string',
rows: 4,
placeholder: 'AI assistant:',
description:
'Sets the stop sequences to use. Use comma to seperate different sequences. Refer to <a target="_blank" href="https://github.com/jmorganca/ollama/blob/main/docs/modelfile.md#valid-parameters-and-values">docs</a> for more details',
optional: true,
additionalParams: true
},
{
label: 'Tail Free Sampling',
name: 'tfsZ',
type: 'number',
description:
'Tail free sampling is used to reduce the impact of less probable tokens from the output. A higher value (e.g., 2.0) will reduce the impact more, while a value of 1.0 disables this setting. (Default: 1). Refer to <a target="_blank" href="https://github.com/jmorganca/ollama/blob/main/docs/modelfile.md#valid-parameters-and-values">docs</a> for more details',
step: 0.1,
optional: true,
additionalParams: true
}
]
}
async init(nodeData: INodeData): Promise<any> {
const temperature = nodeData.inputs?.temperature as string
const baseUrl = nodeData.inputs?.baseUrl as string
const modelName = nodeData.inputs?.modelName as string
const topP = nodeData.inputs?.topP as string
const topK = nodeData.inputs?.topK as string
const mirostat = nodeData.inputs?.mirostat as string
const mirostatEta = nodeData.inputs?.mirostatEta as string
const mirostatTau = nodeData.inputs?.mirostatTau as string
const numCtx = nodeData.inputs?.numCtx as string
const numGqa = nodeData.inputs?.numGqa as string
const numGpu = nodeData.inputs?.numGpu as string
const numThread = nodeData.inputs?.numThread as string
const repeatLastN = nodeData.inputs?.repeatLastN as string
const repeatPenalty = nodeData.inputs?.repeatPenalty as string
const stop = nodeData.inputs?.stop as string
const tfsZ = nodeData.inputs?.tfsZ as string
const cache = nodeData.inputs?.cache as BaseCache
const obj: OllamaInput & BaseLLMParams = {
baseUrl,
temperature: parseFloat(temperature),
model: modelName
}
if (topP) obj.topP = parseFloat(topP)
if (topK) obj.topK = parseFloat(topK)
if (mirostat) obj.mirostat = parseFloat(mirostat)
if (mirostatEta) obj.mirostatEta = parseFloat(mirostatEta)
if (mirostatTau) obj.mirostatTau = parseFloat(mirostatTau)
if (numCtx) obj.numCtx = parseFloat(numCtx)
if (numGqa) obj.numGqa = parseFloat(numGqa)
if (numGpu) obj.numGpu = parseFloat(numGpu)
if (numThread) obj.numThread = parseFloat(numThread)
if (repeatLastN) obj.repeatLastN = parseFloat(repeatLastN)
if (repeatPenalty) obj.repeatPenalty = parseFloat(repeatPenalty)
if (tfsZ) obj.tfsZ = parseFloat(tfsZ)
if (stop) {
const stopSequences = stop.split(',')
obj.stop = stopSequences
}
if (cache) obj.cache = cache
const model = new Ollama(obj)
return model
}
}
module.exports = { nodeClass: Ollama_LLMs }
Binary file not shown.

After

Width:  |  Height:  |  Size: 7.3 KiB

@@ -1,6 +1,8 @@
import { ICommonObject, INode, INodeData, INodeParams } from '../../../src/Interface'
import { getBaseClasses, getCredentialData, getCredentialParam } from '../../../src/utils'
import { OpenAI, OpenAIInput } from 'langchain/llms/openai'
import { BaseLLMParams } from 'langchain/llms/base'
import { BaseCache } from 'langchain/schema'
class OpenAI_LLMs implements INode {
label: string
@@ -17,7 +19,7 @@ class OpenAI_LLMs implements INode {
constructor() {
this.label = 'OpenAI'
this.name = 'openAI'
this.version = 2.0
this.version = 3.0
this.type = 'OpenAI'
this.icon = 'openai.png'
this.category = 'LLMs'
@@ -30,6 +32,12 @@ class OpenAI_LLMs implements INode {
credentialNames: ['openAIApi']
}
this.inputs = [
{
label: 'Cache',
name: 'cache',
type: 'BaseCache',
optional: true
},
{
label: 'Model Name',
name: 'modelName',
@@ -149,7 +157,9 @@ class OpenAI_LLMs implements INode {
const credentialData = await getCredentialData(nodeData.credential ?? '', options)
const openAIApiKey = getCredentialParam('openAIApiKey', credentialData, nodeData)
const obj: Partial<OpenAIInput> & { openAIApiKey?: string } = {
const cache = nodeData.inputs?.cache as BaseCache
const obj: Partial<OpenAIInput> & BaseLLMParams & { openAIApiKey?: string } = {
temperature: parseFloat(temperature),
modelName,
openAIApiKey,
@@ -164,8 +174,9 @@ class OpenAI_LLMs implements INode {
if (batchSize) obj.batchSize = parseInt(batchSize, 10)
if (bestOf) obj.bestOf = parseInt(bestOf, 10)
let parsedBaseOptions: any | undefined = undefined
if (cache) obj.cache = cache
let parsedBaseOptions: any | undefined = undefined
if (baseOptions) {
try {
parsedBaseOptions = typeof baseOptions === 'object' ? baseOptions : JSON.parse(baseOptions)
@@ -1,6 +1,8 @@
import { ICommonObject, INode, INodeData, INodeParams } from '../../../src/Interface'
import { getBaseClasses, getCredentialData, getCredentialParam } from '../../../src/utils'
import { Replicate, ReplicateInput } from 'langchain/llms/replicate'
import { BaseCache } from 'langchain/schema'
import { BaseLLMParams } from 'langchain/llms/base'
class Replicate_LLMs implements INode {
label: string
@@ -17,7 +19,7 @@ class Replicate_LLMs implements INode {
constructor() {
this.label = 'Replicate'
this.name = 'replicate'
this.version = 1.0
this.version = 2.0
this.type = 'Replicate'
this.icon = 'replicate.svg'
this.category = 'LLMs'
@@ -30,6 +32,12 @@ class Replicate_LLMs implements INode {
credentialNames: ['replicateApi']
}
this.inputs = [
{
label: 'Cache',
name: 'cache',
type: 'BaseCache',
optional: true
},
{
label: 'Model',
name: 'model',
@@ -103,7 +111,9 @@ class Replicate_LLMs implements INode {
const name = modelName.split(':')[0].split('/').pop()
const org = modelName.split(':')[0].split('/')[0]
const obj: ReplicateInput = {
const cache = nodeData.inputs?.cache as BaseCache
const obj: ReplicateInput & BaseLLMParams = {
model: `${org}/${name}:${version}`,
apiKey
}
@@ -120,6 +130,8 @@ class Replicate_LLMs implements INode {
}
if (Object.keys(inputs).length) obj.input = inputs
if (cache) obj.cache = cache
const model = new Replicate(obj)
return model
}
@@ -0,0 +1,118 @@
import { INode, INodeData, INodeParams } from '../../../src/Interface'
import { getBaseClasses, getCredentialData, getCredentialParam } from '../../../src/utils'
import { ICommonObject } from '../../../src'
import { BufferMemory, BufferMemoryInput } from 'langchain/memory'
import { UpstashRedisChatMessageHistory } from 'langchain/stores/message/upstash_redis'
class UpstashRedisBackedChatMemory_Memory implements INode {
label: string
name: string
version: number
description: string
type: string
icon: string
category: string
baseClasses: string[]
credential: INodeParams
inputs: INodeParams[]
constructor() {
this.label = 'Upstash Redis-Backed Chat Memory'
this.name = 'upstashRedisBackedChatMemory'
this.version = 1.0
this.type = 'UpstashRedisBackedChatMemory'
this.icon = 'upstash.svg'
this.category = 'Memory'
this.description = 'Summarizes the conversation and stores the memory in Upstash Redis server'
this.baseClasses = [this.type, ...getBaseClasses(BufferMemory)]
this.credential = {
label: 'Connect Credential',
name: 'credential',
type: 'credential',
description: 'Configure password authentication on your upstash redis instance',
credentialNames: ['upstashRedisMemoryApi']
}
this.inputs = [
{
label: 'Upstash Redis REST URL',
name: 'baseURL',
type: 'string',
placeholder: 'https://<your-url>.upstash.io'
},
{
label: 'Session Id',
name: 'sessionId',
type: 'string',
description: 'If not specified, the first CHAT_MESSAGE_ID will be used as sessionId',
default: '',
additionalParams: true,
optional: true
},
{
label: 'Session Timeouts',
name: 'sessionTTL',
type: 'number',
description: 'Omit this parameter to make sessions never expire',
additionalParams: true,
optional: true
}
]
}
async init(nodeData: INodeData, _: string, options: ICommonObject): Promise<any> {
return initalizeUpstashRedis(nodeData, options)
}
async clearSessionMemory(nodeData: INodeData, options: ICommonObject): Promise<void> {
const redis = await initalizeUpstashRedis(nodeData, options)
const sessionId = nodeData.inputs?.sessionId as string
const chatId = options?.chatId as string
options.logger.info(`Clearing Upstash Redis memory session ${sessionId ? sessionId : chatId}`)
await redis.clear()
options.logger.info(`Successfully cleared Upstash Redis memory session ${sessionId ? sessionId : chatId}`)
}
}
const initalizeUpstashRedis = async (nodeData: INodeData, options: ICommonObject): Promise<BufferMemory> => {
const baseURL = nodeData.inputs?.baseURL as string
const sessionId = nodeData.inputs?.sessionId as string
const sessionTTL = nodeData.inputs?.sessionTTL as string
const chatId = options?.chatId as string
let isSessionIdUsingChatMessageId = false
if (!sessionId && chatId) isSessionIdUsingChatMessageId = true
const credentialData = await getCredentialData(nodeData.credential ?? '', options)
const upstashRestToken = getCredentialParam('upstashRestToken', credentialData, nodeData)
const redisChatMessageHistory = new UpstashRedisChatMessageHistory({
sessionId: sessionId ? sessionId : chatId,
sessionTTL: sessionTTL ? parseInt(sessionTTL, 10) : undefined,
config: {
url: baseURL,
token: upstashRestToken
}
})
const memory = new BufferMemoryExtended({
chatHistory: redisChatMessageHistory,
isSessionIdUsingChatMessageId
})
return memory
}
interface BufferMemoryExtendedInput {
isSessionIdUsingChatMessageId: boolean
}
class BufferMemoryExtended extends BufferMemory {
isSessionIdUsingChatMessageId? = false
constructor(fields: BufferMemoryInput & Partial<BufferMemoryExtendedInput>) {
super(fields)
this.isSessionIdUsingChatMessageId = fields.isSessionIdUsingChatMessageId
}
}
module.exports = { nodeClass: UpstashRedisBackedChatMemory_Memory }
@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="256px" height="341px" viewBox="0 0 256 341" version="1.1" xmlns="http://www.w3.org/2000/svg" preserveAspectRatio="xMidYMid">
<title>upstash</title>
<g>
<path d="M0,298.416784 C56.5542815,354.970323 148.246768,354.970323 204.801032,298.416784 C261.354571,241.86252 261.354571,150.170106 204.801032,93.6158424 L179.200462,119.215688 C221.61634,161.631567 221.61634,230.401059 179.200462,272.816213 C136.785307,315.232092 68.0157428,315.232092 25.5998642,272.816213 L0,298.416784 Z" fill="#00C98D"></path>
<path d="M51.200362,247.216367 C79.4772765,275.493137 125.323122,275.493137 153.600615,247.216367 C181.877385,218.939598 181.877385,173.093028 153.600615,144.816259 L128.000769,170.416105 C142.139154,184.55449 142.139154,207.477412 128.000769,221.616521 C113.86166,235.754906 90.9387378,235.754906 76.800353,221.616521 L51.200362,247.216367 Z" fill="#00C98D"></path>
<path d="M256,42.415426 C199.445737,-14.1384753 107.753322,-14.1384753 51.1994207,42.415426 C-5.35485714,98.9696894 -5.35485714,190.662104 51.1994207,247.216367 L76.7989048,221.616521 C34.3841124,179.200643 34.3841124,110.431151 76.7989048,68.0159962 C119.214783,25.6001177 187.984275,25.6001177 230.39943,68.0159962 L256,42.415426 Z" fill="#00C98D"></path>
<path d="M204.800308,93.6158424 C176.523538,65.3390727 130.676245,65.3390727 102.399475,93.6158424 C74.1219813,121.893336 74.1219813,167.739181 102.399475,196.015951 L127.999321,170.416105 C113.860936,156.27772 113.860936,133.354797 127.999321,119.215688 C142.137706,105.077304 165.060629,105.077304 179.199738,119.215688 L204.800308,93.6158424 Z" fill="#00C98D"></path>
<path d="M256,42.415426 C199.445737,-14.1384753 107.753322,-14.1384753 51.1994207,42.415426 C-5.35485714,98.9696894 -5.35485714,190.662104 51.1994207,247.216367 L76.7989048,221.616521 C34.3841124,179.200643 34.3841124,110.431151 76.7989048,68.0159962 C119.214783,25.6001177 187.984275,25.6001177 230.39943,68.0159962 L256,42.415426 Z" fill-opacity="0.4" fill="#FFFFFF"></path>
<path d="M204.800308,93.6158424 C176.523538,65.3390727 130.676245,65.3390727 102.399475,93.6158424 C74.1219813,121.893336 74.1219813,167.739181 102.399475,196.015951 L127.999321,170.416105 C113.860936,156.27772 113.860936,133.354797 127.999321,119.215688 C142.137706,105.077304 165.060629,105.077304 179.199738,119.215688 L204.800308,93.6158424 Z" fill-opacity="0.4" fill="#FFFFFF"></path>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.4 KiB

@@ -53,7 +53,7 @@ class ChatPromptTemplate_Prompts implements INode {
const humanMessagePrompt = nodeData.inputs?.humanMessagePrompt as string
const promptValuesStr = nodeData.inputs?.promptValues as string
const prompt = ChatPromptTemplate.fromPromptMessages([
const prompt = ChatPromptTemplate.fromMessages([
SystemMessagePromptTemplate.fromTemplate(systemMessagePrompt),
HumanMessagePromptTemplate.fromTemplate(humanMessagePrompt)
])
@@ -23,12 +23,6 @@ class CharacterTextSplitter_TextSplitters implements INode {
this.description = `splits only on one type of character (defaults to "\\n\\n").`
this.baseClasses = [this.type, ...getBaseClasses(CharacterTextSplitter)]
this.inputs = [
{
label: 'Separator',
name: 'separator',
type: 'string',
optional: true
},
{
label: 'Chunk Size',
name: 'chunkSize',
@@ -41,6 +35,14 @@ class CharacterTextSplitter_TextSplitters implements INode {
name: 'chunkOverlap',
type: 'number',
optional: true
},
{
label: 'Custom Separator',
name: 'separator',
type: 'string',
placeholder: `" "`,
description: 'Seperator to determine when to split the text, will override the default separator',
optional: true
}
]
}
@@ -16,7 +16,7 @@ class RecursiveCharacterTextSplitter_TextSplitters implements INode {
constructor() {
this.label = 'Recursive Character Text Splitter'
this.name = 'recursiveCharacterTextSplitter'
this.version = 1.0
this.version = 2.0
this.type = 'RecursiveCharacterTextSplitter'
this.icon = 'textsplitter.svg'
this.category = 'Text Splitters'
@@ -35,6 +35,15 @@ class RecursiveCharacterTextSplitter_TextSplitters implements INode {
name: 'chunkOverlap',
type: 'number',
optional: true
},
{
label: 'Custom Separators',
name: 'separators',
type: 'string',
rows: 4,
description: 'Array of custom seperators to determine when to split the text, will override the default separators',
placeholder: `["|", "##", ">", "-"]`,
optional: true
}
]
}
@@ -42,11 +51,19 @@ class RecursiveCharacterTextSplitter_TextSplitters implements INode {
async init(nodeData: INodeData): Promise<any> {
const chunkSize = nodeData.inputs?.chunkSize as string
const chunkOverlap = nodeData.inputs?.chunkOverlap as string
const separators = nodeData.inputs?.separators as string
const obj = {} as RecursiveCharacterTextSplitterParams
if (chunkSize) obj.chunkSize = parseInt(chunkSize, 10)
if (chunkOverlap) obj.chunkOverlap = parseInt(chunkOverlap, 10)
if (separators) {
try {
obj.separators = JSON.parse(separators)
} catch (e) {
throw new Error(e)
}
}
const splitter = new RecursiveCharacterTextSplitter(obj)
@@ -0,0 +1,193 @@
import {
getBaseClasses,
getCredentialData,
getCredentialParam,
ICommonObject,
INodeData,
INodeOutputsValue,
INodeParams
} from '../../../src'
import { Client, ClientOptions } from '@elastic/elasticsearch'
import { ElasticClientArgs, ElasticVectorSearch } from 'langchain/vectorstores/elasticsearch'
import { Embeddings } from 'langchain/embeddings/base'
import { VectorStore } from 'langchain/vectorstores/base'
import { Document } from 'langchain/document'
export abstract class ElasticSearchBase {
label: string
name: string
version: number
description: string
type: string
icon: string
category: string
baseClasses: string[]
inputs: INodeParams[]
credential: INodeParams
outputs: INodeOutputsValue[]
protected constructor() {
this.type = 'Elasticsearch'
this.icon = 'elasticsearch.png'
this.category = 'Vector Stores'
this.baseClasses = [this.type, 'VectorStoreRetriever', 'BaseRetriever']
this.credential = {
label: 'Connect Credential',
name: 'credential',
type: 'credential',
credentialNames: ['elasticsearchApi', 'elasticSearchUserPassword']
}
this.inputs = [
{
label: 'Embeddings',
name: 'embeddings',
type: 'Embeddings'
},
{
label: 'Index Name',
name: 'indexName',
placeholder: '<INDEX_NAME>',
type: 'string'
},
{
label: 'Top K',
name: 'topK',
description: 'Number of top results to fetch. Default to 4',
placeholder: '4',
type: 'number',
additionalParams: true,
optional: true
},
{
label: 'Similarity',
name: 'similarity',
description: 'Similarity measure used in Elasticsearch.',
type: 'options',
default: 'l2_norm',
options: [
{
label: 'l2_norm',
name: 'l2_norm'
},
{
label: 'dot_product',
name: 'dot_product'
},
{
label: 'cosine',
name: 'cosine'
}
],
additionalParams: true,
optional: true
}
]
this.outputs = [
{
label: 'Elasticsearch Retriever',
name: 'retriever',
baseClasses: this.baseClasses
},
{
label: 'Elasticsearch Vector Store',
name: 'vectorStore',
baseClasses: [this.type, ...getBaseClasses(ElasticVectorSearch)]
}
]
}
abstract constructVectorStore(
embeddings: Embeddings,
elasticSearchClientArgs: ElasticClientArgs,
docs: Document<Record<string, any>>[] | undefined
): Promise<VectorStore>
async init(nodeData: INodeData, _: string, options: ICommonObject, docs: Document<Record<string, any>>[] | undefined): Promise<any> {
const credentialData = await getCredentialData(nodeData.credential ?? '', options)
const endPoint = getCredentialParam('endpoint', credentialData, nodeData)
const cloudId = getCredentialParam('cloudId', credentialData, nodeData)
const indexName = nodeData.inputs?.indexName as string
const embeddings = nodeData.inputs?.embeddings as Embeddings
const topK = nodeData.inputs?.topK as string
const similarityMeasure = nodeData.inputs?.similarityMeasure as string
const k = topK ? parseFloat(topK) : 4
const output = nodeData.outputs?.output as string
const elasticSearchClientArgs = this.prepareClientArgs(endPoint, cloudId, credentialData, nodeData, similarityMeasure, indexName)
const vectorStore = await this.constructVectorStore(embeddings, elasticSearchClientArgs, docs)
if (output === 'retriever') {
return vectorStore.asRetriever(k)
} else if (output === 'vectorStore') {
;(vectorStore as any).k = k
return vectorStore
}
return vectorStore
}
protected prepareConnectionOptions(
endPoint: string | undefined,
cloudId: string | undefined,
credentialData: ICommonObject,
nodeData: INodeData
) {
let elasticSearchClientOptions: ClientOptions = {}
if (endPoint) {
let apiKey = getCredentialParam('apiKey', credentialData, nodeData)
elasticSearchClientOptions = {
node: endPoint,
auth: {
apiKey: apiKey
}
}
} else if (cloudId) {
let username = getCredentialParam('username', credentialData, nodeData)
let password = getCredentialParam('password', credentialData, nodeData)
elasticSearchClientOptions = {
cloud: {
id: cloudId
},
auth: {
username: username,
password: password
}
}
}
return elasticSearchClientOptions
}
protected prepareClientArgs(
endPoint: string | undefined,
cloudId: string | undefined,
credentialData: ICommonObject,
nodeData: INodeData,
similarityMeasure: string,
indexName: string
) {
let elasticSearchClientOptions = this.prepareConnectionOptions(endPoint, cloudId, credentialData, nodeData)
let vectorSearchOptions = {}
switch (similarityMeasure) {
case 'dot_product':
vectorSearchOptions = {
similarity: 'dot_product'
}
break
case 'cosine':
vectorSearchOptions = {
similarity: 'cosine'
}
break
default:
vectorSearchOptions = {
similarity: 'l2_norm'
}
}
const elasticSearchClientArgs: ElasticClientArgs = {
client: new Client(elasticSearchClientOptions),
indexName: indexName,
vectorSearchOptions: vectorSearchOptions
}
return elasticSearchClientArgs
}
}
@@ -0,0 +1,31 @@
import { ICommonObject, INode, INodeData } from '../../../src/Interface'
import { Embeddings } from 'langchain/embeddings/base'
import { ElasticClientArgs, ElasticVectorSearch } from 'langchain/vectorstores/elasticsearch'
import { ElasticSearchBase } from './ElasticSearchBase'
import { VectorStore } from 'langchain/vectorstores/base'
import { Document } from 'langchain/document'
class ElasicsearchExisting_VectorStores extends ElasticSearchBase implements INode {
constructor() {
super()
this.label = 'Elasticsearch Load Existing Index'
this.name = 'ElasticsearchIndex'
this.version = 1.0
this.description = 'Load existing index from Elasticsearch (i.e: Document has been upserted)'
}
async constructVectorStore(
embeddings: Embeddings,
elasticSearchClientArgs: ElasticClientArgs,
_: Document<Record<string, any>>[] | undefined
): Promise<VectorStore> {
return await ElasticVectorSearch.fromExistingIndex(embeddings, elasticSearchClientArgs)
}
async init(nodeData: INodeData, _: string, options: ICommonObject): Promise<any> {
return super.init(nodeData, _, options, undefined)
}
}
module.exports = { nodeClass: ElasicsearchExisting_VectorStores }
@@ -0,0 +1,55 @@
import { ICommonObject, INode, INodeData } from '../../../src/Interface'
import { Embeddings } from 'langchain/embeddings/base'
import { Document } from 'langchain/document'
import { ElasticClientArgs, ElasticVectorSearch } from 'langchain/vectorstores/elasticsearch'
import { flatten } from 'lodash'
import { ElasticSearchBase } from './ElasticSearchBase'
import { VectorStore } from 'langchain/vectorstores/base'
class ElasicsearchUpsert_VectorStores extends ElasticSearchBase implements INode {
constructor() {
super()
this.label = 'Elasticsearch Upsert Document'
this.name = 'ElasticsearchUpsert'
this.version = 1.0
this.description = 'Upsert documents to Elasticsearch'
this.inputs.unshift({
label: 'Document',
name: 'document',
type: 'Document',
list: true
})
}
async constructVectorStore(
embeddings: Embeddings,
elasticSearchClientArgs: ElasticClientArgs,
docs: Document<Record<string, any>>[]
): Promise<VectorStore> {
const vectorStore = new ElasticVectorSearch(embeddings, elasticSearchClientArgs)
await vectorStore.addDocuments(docs)
return vectorStore
}
async init(nodeData: INodeData, _: string, options: ICommonObject): Promise<any> {
const docs = nodeData.inputs?.document as Document[]
const flattenDocs = docs && docs.length ? flatten(docs) : []
const finalDocs = []
for (let i = 0; i < flattenDocs.length; i += 1) {
finalDocs.push(new Document(flattenDocs[i]))
}
// The following code is a workaround for a bug (Langchain Issue #1589) in the underlying library.
// Store does not support object in metadata and fail silently
finalDocs.forEach((d) => {
delete d.metadata.pdf
delete d.metadata.loc
})
// end of workaround
return super.init(nodeData, _, options, flattenDocs)
}
}
module.exports = { nodeClass: ElasicsearchUpsert_VectorStores }
Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

@@ -1,5 +1,5 @@
import { ICommonObject, INode, INodeData, INodeOutputsValue, INodeParams } from '../../../src/Interface'
import { PineconeClient } from '@pinecone-database/pinecone'
import { Pinecone } from '@pinecone-database/pinecone'
import { PineconeLibArgs, PineconeStore } from 'langchain/vectorstores/pinecone'
import { Embeddings } from 'langchain/embeddings/base'
import { getBaseClasses, getCredentialData, getCredentialParam } from '../../../src/utils'
@@ -95,8 +95,7 @@ class Pinecone_Existing_VectorStores implements INode {
const pineconeApiKey = getCredentialParam('pineconeApiKey', credentialData, nodeData)
const pineconeEnv = getCredentialParam('pineconeEnv', credentialData, nodeData)
const client = new PineconeClient()
await client.init({
const client = new Pinecone({
apiKey: pineconeApiKey,
environment: pineconeEnv
})
@@ -1,5 +1,5 @@
import { ICommonObject, INode, INodeData, INodeOutputsValue, INodeParams } from '../../../src/Interface'
import { PineconeClient } from '@pinecone-database/pinecone'
import { Pinecone } from '@pinecone-database/pinecone'
import { PineconeLibArgs, PineconeStore } from 'langchain/vectorstores/pinecone'
import { Embeddings } from 'langchain/embeddings/base'
import { Document } from 'langchain/document'
@@ -96,8 +96,7 @@ class PineconeUpsert_VectorStores implements INode {
const pineconeApiKey = getCredentialParam('pineconeApiKey', credentialData, nodeData)
const pineconeEnv = getCredentialParam('pineconeEnv', credentialData, nodeData)
const client = new PineconeClient()
await client.init({
const client = new Pinecone({
apiKey: pineconeApiKey,
environment: pineconeEnv
})

Before

Width:  |  Height:  |  Size: 2.4 KiB

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

@@ -32,7 +32,7 @@ class VectaraExisting_VectorStores implements INode {
}
this.inputs = [
{
label: 'Vectara Metadata Filter',
label: 'Metadata Filter',
name: 'filter',
description:
'Filter to apply to Vectara metadata. Refer to the <a target="_blank" href="https://docs.flowiseai.com/vector-stores/vectara">documentation</a> on how to use Vectara filters with Flowise.',
@@ -105,7 +105,8 @@ class VectaraExisting_VectorStores implements INode {
const vectaraArgs: VectaraLibArgs = {
apiKey: apiKey,
customerId: customerId,
corpusId: corpusId
corpusId: corpusId,
source: 'flowise'
}
const vectaraFilter: VectaraFilter = {}
@@ -39,7 +39,7 @@ class VectaraUpload_VectorStores implements INode {
type: 'file'
},
{
label: 'Vectara Metadata Filter',
label: 'Metadata Filter',
name: 'filter',
description:
'Filter to apply to Vectara metadata. Refer to the <a target="_blank" href="https://docs.flowiseai.com/vector-stores/vectara">documentation</a> on how to use Vectara filters with Flowise.',
@@ -113,7 +113,8 @@ class VectaraUpload_VectorStores implements INode {
const vectaraArgs: VectaraLibArgs = {
apiKey: apiKey,
customerId: customerId,
corpusId: corpusId
corpusId: corpusId,
source: 'flowise'
}
const vectaraFilter: VectaraFilter = {}
@@ -41,7 +41,7 @@ class VectaraUpsert_VectorStores implements INode {
list: true
},
{
label: 'Vectara Metadata Filter',
label: 'Metadata Filter',
name: 'filter',
description:
'Filter to apply to Vectara metadata. Refer to the <a target="_blank" href="https://docs.flowiseai.com/vector-stores/vectara">documentation</a> on how to use Vectara filters with Flowise.',
@@ -116,7 +116,8 @@ class VectaraUpsert_VectorStores implements INode {
const vectaraArgs: VectaraLibArgs = {
apiKey: apiKey,
customerId: customerId,
corpusId: corpusId
corpusId: corpusId,
source: 'flowise'
}
const vectaraFilter: VectaraFilter = {}
+11 -3
View File
@@ -1,6 +1,6 @@
{
"name": "flowise-components",
"version": "1.3.7",
"version": "1.3.10",
"description": "Flowiseai Components",
"main": "dist/src/index",
"types": "dist/src/index.d.ts",
@@ -16,18 +16,23 @@
},
"license": "SEE LICENSE IN LICENSE.md",
"dependencies": {
"@aws-sdk/client-bedrock-runtime": "3.422.0",
"@aws-sdk/client-dynamodb": "^3.360.0",
"@aws-sdk/client-s3": "^3.427.0",
"@dqbd/tiktoken": "^1.0.7",
"@elastic/elasticsearch": "^8.9.0",
"@getzep/zep-js": "^0.6.3",
"@gomomento/sdk": "^1.40.2",
"@google-ai/generativelanguage": "^0.2.1",
"@huggingface/inference": "^2.6.1",
"@notionhq/client": "^2.2.8",
"@opensearch-project/opensearch": "^1.2.0",
"@pinecone-database/pinecone": "^0.0.14",
"@pinecone-database/pinecone": "^1.1.1",
"@qdrant/js-client-rest": "^1.2.2",
"@supabase/supabase-js": "^2.29.0",
"@types/js-yaml": "^4.0.5",
"@types/jsdom": "^21.1.1",
"@upstash/redis": "^1.22.1",
"@zilliz/milvus2-sdk-node": "^2.2.24",
"apify-client": "^2.7.1",
"axios": "^0.27.2",
@@ -42,7 +47,8 @@
"google-auth-library": "^9.0.0",
"graphql": "^16.6.0",
"html-to-text": "^9.0.5",
"langchain": "^0.0.157",
"ioredis": "^5.3.2",
"langchain": "^0.0.165",
"langfuse-langchain": "^1.0.14-alpha.0",
"langsmith": "^0.0.32",
"linkifyjs": "^4.1.1",
@@ -53,6 +59,7 @@
"node-fetch": "^2.6.11",
"node-html-markdown": "^1.3.0",
"notion-to-md": "^3.1.1",
"object-hash": "^3.0.0",
"pdf-parse": "^1.1.1",
"pdfjs-dist": "^3.7.107",
"pg": "^8.11.2",
@@ -69,6 +76,7 @@
"devDependencies": {
"@types/gulp": "4.0.9",
"@types/node-fetch": "2.6.2",
"@types/object-hash": "^3.0.2",
"@types/pg": "^8.10.2",
"@types/ws": "^8.5.3",
"gulp": "^4.0.2",
+1
View File
@@ -5,6 +5,7 @@
export type NodeParamsType =
| 'asyncOptions'
| 'options'
| 'multiOptions'
| 'string'
| 'number'
| 'boolean'
+27 -10
View File
@@ -151,6 +151,7 @@ export class CustomChainHandler extends BaseCallbackHandler {
socketIOClientId = ''
skipK = 0 // Skip streaming for first K numbers of handleLLMStart
returnSourceDocuments = false
cachedResponse = true
constructor(socketIO: Server, socketIOClientId: string, skipK?: number, returnSourceDocuments?: boolean) {
super()
@@ -161,6 +162,7 @@ export class CustomChainHandler extends BaseCallbackHandler {
}
handleLLMStart() {
this.cachedResponse = false
if (this.skipK > 0) this.skipK -= 1
}
@@ -178,9 +180,30 @@ export class CustomChainHandler extends BaseCallbackHandler {
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)
handleChainEnd(outputs: ChainValues, _: string, parentRunId?: string): void | Promise<void> {
/*
Langchain does not call handleLLMStart, handleLLMEnd, handleLLMNewToken when the chain is cached.
Callback Order is "Chain Start -> LLM Start --> LLM Token --> LLM End -> Chain End" for normal responses.
Callback Order is "Chain Start -> Chain End" for cached responses.
*/
if (this.cachedResponse && parentRunId === undefined) {
const cachedValue = outputs.text ?? outputs.response ?? outputs.output ?? outputs.output_text
//split at whitespace, and keep the whitespace. This is to preserve the original formatting.
const result = cachedValue.split(/(\s+)/)
result.forEach((token: string, index: number) => {
if (index === 0) {
this.socketIO.to(this.socketIOClientId).emit('start', token)
}
this.socketIO.to(this.socketIOClientId).emit('token', token)
})
if (this.returnSourceDocuments) {
this.socketIO.to(this.socketIOClientId).emit('sourceDocuments', outputs?.sourceDocuments)
}
this.socketIO.to(this.socketIOClientId).emit('end')
} else {
if (this.returnSourceDocuments) {
this.socketIO.to(this.socketIOClientId).emit('sourceDocuments', outputs?.sourceDocuments)
}
}
}
}
@@ -215,23 +238,17 @@ export const additionalCallbacks = async (nodeData: INodeData, options: ICommonO
})
callbacks.push(tracer)
} else if (provider === 'langFuse') {
const flushAt = analytic[provider].flushAt as string
const flushInterval = analytic[provider].flushInterval as string
const requestTimeout = analytic[provider].requestTimeout as string
const release = analytic[provider].release as string
const langFuseSecretKey = getCredentialParam('langFuseSecretKey', credentialData, nodeData)
const langFusePublicKey = getCredentialParam('langFusePublicKey', credentialData, nodeData)
const langFuseEndpoint = getCredentialParam('langFuseEndpoint', credentialData, nodeData)
const langFuseOptions: ICommonObject = {
const langFuseOptions: any = {
secretKey: langFuseSecretKey,
publicKey: langFusePublicKey,
baseUrl: langFuseEndpoint ?? 'https://cloud.langfuse.com'
}
if (flushAt) langFuseOptions.flushAt = parseInt(flushAt, 10)
if (flushInterval) langFuseOptions.flushInterval = parseInt(flushInterval, 10)
if (requestTimeout) langFuseOptions.requestTimeout = parseInt(requestTimeout, 10)
if (release) langFuseOptions.release = release
const handler = new CallbackHandler(langFuseOptions)
+1 -1
View File
@@ -533,7 +533,7 @@ export const mapChatHistory = (options: ICommonObject): ChatMessageHistory => {
* @param {IMessage[]} chatHistory
* @returns {string}
*/
export const convertChatHistoryToText = (chatHistory: IMessage[]): string => {
export const convertChatHistoryToText = (chatHistory: IMessage[] = []): string => {
return chatHistory
.map((chatMessage) => {
if (chatMessage.type === 'apiMessage') {
+2
View File
@@ -0,0 +1,2 @@
dev eol=lf
run eol=lf
@@ -89,7 +89,7 @@
"id": "chatOpenAI_1",
"label": "ChatOpenAI",
"name": "chatOpenAI",
"version": 1,
"version": 2,
"type": "ChatOpenAI",
"baseClasses": ["ChatOpenAI", "BaseChatModel", "BaseLanguageModel"],
"category": "Chat Models",
@@ -201,7 +201,15 @@
"id": "chatOpenAI_1-input-basepath-string"
}
],
"inputAnchors": [],
"inputAnchors": [
{
"label": "Cache",
"name": "cache",
"type": "BaseCache",
"optional": true,
"id": "chatOpenAI_1-input-cache-BaseCache"
}
],
"inputs": {
"modelName": "gpt-3.5-turbo",
"temperature": 0.9,
@@ -392,7 +400,7 @@
"id": "chatOpenAI_2",
"label": "ChatOpenAI",
"name": "chatOpenAI",
"version": 1,
"version": 2,
"type": "ChatOpenAI",
"baseClasses": ["ChatOpenAI", "BaseChatModel", "BaseLanguageModel"],
"category": "Chat Models",
@@ -504,7 +512,15 @@
"id": "chatOpenAI_2-input-basepath-string"
}
],
"inputAnchors": [],
"inputAnchors": [
{
"label": "Cache",
"name": "cache",
"type": "BaseCache",
"optional": true,
"id": "chatOpenAI_2-input-cache-BaseCache"
}
],
"inputs": {
"modelName": "gpt-3.5-turbo",
"temperature": 0.9,
@@ -397,7 +397,7 @@
"id": "chatOpenAI_2",
"label": "ChatOpenAI",
"name": "chatOpenAI",
"version": 1,
"version": 2,
"type": "ChatOpenAI",
"baseClasses": ["ChatOpenAI", "BaseChatModel", "BaseLanguageModel"],
"category": "Chat Models",
@@ -509,7 +509,15 @@
"id": "chatOpenAI_2-input-basepath-string"
}
],
"inputAnchors": [],
"inputAnchors": [
{
"label": "Cache",
"name": "cache",
"type": "BaseCache",
"optional": true,
"id": "chatOpenAI_2-input-cache-BaseCache"
}
],
"inputs": {
"modelName": "gpt-3.5-turbo",
"temperature": 0.9,
@@ -551,7 +559,7 @@
"id": "chatOpenAI_1",
"label": "ChatOpenAI",
"name": "chatOpenAI",
"version": 1,
"version": 2,
"type": "ChatOpenAI",
"baseClasses": ["ChatOpenAI", "BaseChatModel", "BaseLanguageModel"],
"category": "Chat Models",
@@ -663,7 +671,15 @@
"id": "chatOpenAI_1-input-basepath-string"
}
],
"inputAnchors": [],
"inputAnchors": [
{
"label": "Cache",
"name": "cache",
"type": "BaseCache",
"optional": true,
"id": "chatOpenAI_1-input-cache-BaseCache"
}
],
"inputs": {
"modelName": "gpt-3.5-turbo",
"temperature": 0.9,
@@ -705,7 +721,7 @@
"id": "chatOpenAI_3",
"label": "ChatOpenAI",
"name": "chatOpenAI",
"version": 1,
"version": 2,
"type": "ChatOpenAI",
"baseClasses": ["ChatOpenAI", "BaseChatModel", "BaseLanguageModel"],
"category": "Chat Models",
@@ -817,7 +833,15 @@
"id": "chatOpenAI_3-input-basepath-string"
}
],
"inputAnchors": [],
"inputAnchors": [
{
"label": "Cache",
"name": "cache",
"type": "BaseCache",
"optional": true,
"id": "chatOpenAI_3-input-cache-BaseCache"
}
],
"inputs": {
"modelName": "gpt-3.5-turbo",
"temperature": 0.9,
@@ -169,14 +169,14 @@
"id": "chatOpenAI_0",
"position": {
"x": 1226.7977900193628,
"y": 48.01100655894436
"y": -22.01100655894436
},
"type": "customNode",
"data": {
"id": "chatOpenAI_0",
"label": "ChatOpenAI",
"name": "chatOpenAI",
"version": 1,
"version": 2,
"type": "ChatOpenAI",
"baseClasses": ["ChatOpenAI", "BaseChatModel", "BaseLanguageModel"],
"category": "Chat Models",
@@ -288,7 +288,15 @@
"id": "chatOpenAI_0-input-basepath-string"
}
],
"inputAnchors": [],
"inputAnchors": [
{
"label": "Cache",
"name": "cache",
"type": "BaseCache",
"optional": true,
"id": "chatOpenAI_0-input-cache-BaseCache"
}
],
"inputs": {
"modelName": "gpt-3.5-turbo",
"temperature": 0.9,
@@ -313,7 +321,7 @@
"selected": false,
"positionAbsolute": {
"x": 1226.7977900193628,
"y": 48.01100655894436
"y": -22.01100655894436
},
"dragging": false
},
@@ -252,7 +252,7 @@
"id": "chatOpenAI_0",
"label": "ChatOpenAI",
"name": "chatOpenAI",
"version": 1,
"version": 2,
"type": "ChatOpenAI",
"baseClasses": ["ChatOpenAI", "BaseChatModel", "BaseLanguageModel"],
"category": "Chat Models",
@@ -364,7 +364,15 @@
"id": "chatOpenAI_0-input-basepath-string"
}
],
"inputAnchors": [],
"inputAnchors": [
{
"label": "Cache",
"name": "cache",
"type": "BaseCache",
"optional": true,
"id": "chatOpenAI_0-input-cache-BaseCache"
}
],
"inputs": {
"modelName": "gpt-3.5-turbo",
"temperature": 0.9,
@@ -78,7 +78,7 @@
"id": "chatOpenAI_0",
"label": "ChatOpenAI",
"name": "chatOpenAI",
"version": 1,
"version": 2,
"type": "ChatOpenAI",
"baseClasses": ["ChatOpenAI", "BaseChatModel", "BaseLanguageModel"],
"category": "Chat Models",
@@ -190,7 +190,15 @@
"id": "chatOpenAI_0-input-basepath-string"
}
],
"inputAnchors": [],
"inputAnchors": [
{
"label": "Cache",
"name": "cache",
"type": "BaseCache",
"optional": true,
"id": "chatOpenAI_0-input-cache-BaseCache"
}
],
"inputs": {
"modelName": "gpt-3.5-turbo",
"temperature": 0.9,
@@ -70,7 +70,7 @@
"id": "chatOpenAI_0",
"label": "ChatOpenAI",
"name": "chatOpenAI",
"version": 1,
"version": 2,
"type": "ChatOpenAI",
"baseClasses": ["ChatOpenAI", "BaseChatModel", "BaseLanguageModel"],
"category": "Chat Models",
@@ -182,7 +182,15 @@
"id": "chatOpenAI_0-input-basepath-string"
}
],
"inputAnchors": [],
"inputAnchors": [
{
"label": "Cache",
"name": "cache",
"type": "BaseCache",
"optional": true,
"id": "chatOpenAI_0-input-cache-BaseCache"
}
],
"inputs": {
"modelName": "gpt-3.5-turbo",
"temperature": 0.9,
@@ -215,7 +215,7 @@
"id": "chatOpenAI_0",
"label": "ChatOpenAI",
"name": "chatOpenAI",
"version": 1,
"version": 2,
"type": "ChatOpenAI",
"baseClasses": ["ChatOpenAI", "BaseChatModel", "BaseLanguageModel"],
"category": "Chat Models",
@@ -327,7 +327,15 @@
"id": "chatOpenAI_0-input-basepath-string"
}
],
"inputAnchors": [],
"inputAnchors": [
{
"label": "Cache",
"name": "cache",
"type": "BaseCache",
"optional": true,
"id": "chatOpenAI_0-input-cache-BaseCache"
}
],
"inputs": {
"modelName": "gpt-3.5-turbo",
"temperature": 0.9,
@@ -141,14 +141,14 @@
"id": "chatAnthropic_0",
"position": {
"x": 800.5525382783799,
"y": -76.7988221837009
"y": -130.7988221837009
},
"type": "customNode",
"data": {
"id": "chatAnthropic_0",
"label": "ChatAnthropic",
"name": "chatAnthropic",
"version": 1,
"version": 2,
"type": "ChatAnthropic",
"baseClasses": ["ChatAnthropic", "BaseChatModel", "BaseLanguageModel"],
"category": "Chat Models",
@@ -258,7 +258,15 @@
"id": "chatAnthropic_0-input-topK-number"
}
],
"inputAnchors": [],
"inputAnchors": [
{
"label": "Cache",
"name": "cache",
"type": "BaseCache",
"optional": true,
"id": "chatAnthropic_0-input-cache-BaseCache"
}
],
"inputs": {
"modelName": "claude-2",
"temperature": 0.9,
@@ -280,7 +288,7 @@
"selected": false,
"positionAbsolute": {
"x": 800.5525382783799,
"y": -76.7988221837009
"y": -130.7988221837009
},
"dragging": false
},
@@ -157,7 +157,7 @@
"id": "chatOpenAI_0",
"label": "ChatOpenAI",
"name": "chatOpenAI",
"version": 1,
"version": 2,
"type": "ChatOpenAI",
"baseClasses": ["ChatOpenAI", "BaseChatModel", "BaseLanguageModel"],
"category": "Chat Models",
@@ -269,7 +269,15 @@
"id": "chatOpenAI_0-input-basepath-string"
}
],
"inputAnchors": [],
"inputAnchors": [
{
"label": "Cache",
"name": "cache",
"type": "BaseCache",
"optional": true,
"id": "chatOpenAI_0-input-cache-BaseCache"
}
],
"inputs": {
"modelName": "gpt-3.5-turbo",
"temperature": 0.9,
@@ -13,7 +13,7 @@
"data": {
"id": "chatOpenAI_0",
"label": "ChatOpenAI",
"version": 1,
"version": 2,
"name": "chatOpenAI",
"type": "ChatOpenAI",
"baseClasses": ["ChatOpenAI", "BaseChatModel", "BaseLanguageModel"],
@@ -126,7 +126,15 @@
"id": "chatOpenAI_0-input-basepath-string"
}
],
"inputAnchors": [],
"inputAnchors": [
{
"label": "Cache",
"name": "cache",
"type": "BaseCache",
"optional": true,
"id": "chatOpenAI_0-input-cache-BaseCache"
}
],
"inputs": {
"modelName": "gpt-3.5-turbo-16k",
"temperature": "0",
@@ -7,14 +7,14 @@
"id": "chatOpenAI_0",
"position": {
"x": 1184.1176114500388,
"y": -44.15535835370571
"y": -74.15535835370571
},
"type": "customNode",
"data": {
"id": "chatOpenAI_0",
"label": "ChatOpenAI",
"name": "chatOpenAI",
"version": 1,
"version": 2,
"type": "ChatOpenAI",
"baseClasses": ["ChatOpenAI", "BaseChatModel", "BaseLanguageModel"],
"category": "Chat Models",
@@ -126,7 +126,15 @@
"id": "chatOpenAI_0-input-basepath-string"
}
],
"inputAnchors": [],
"inputAnchors": [
{
"label": "Cache",
"name": "cache",
"type": "BaseCache",
"optional": true,
"id": "chatOpenAI_0-input-cache-BaseCache"
}
],
"inputs": {
"modelName": "gpt-3.5-turbo",
"temperature": "0",
@@ -150,7 +158,7 @@
},
"positionAbsolute": {
"x": 1184.1176114500388,
"y": -44.15535835370571
"y": -74.15535835370571
},
"selected": false,
"dragging": false
@@ -418,7 +426,7 @@
"id": "textFile_0",
"label": "Text File",
"name": "textFile",
"version": 1,
"version": 2,
"type": "Document",
"baseClasses": ["Document"],
"category": "Document Loaders",
@@ -455,13 +463,29 @@
},
"outputAnchors": [
{
"id": "textFile_0-output-textFile-Document",
"name": "textFile",
"label": "Document",
"type": "Document"
"name": "output",
"label": "Output",
"type": "options",
"options": [
{
"id": "textFile_0-output-document-Document",
"name": "document",
"label": "Document",
"type": "Document"
},
{
"id": "textFile_0-output-text-string|json",
"name": "text",
"label": "Text",
"type": "string | json"
}
],
"default": "document"
}
],
"outputs": {},
"outputs": {
"output": "document"
},
"selected": false
},
"selected": false,
@@ -386,7 +386,7 @@
"id": "chatOpenAI_0",
"label": "ChatOpenAI",
"name": "chatOpenAI",
"version": 1,
"version": 2,
"type": "ChatOpenAI",
"baseClasses": ["ChatOpenAI", "BaseChatModel", "BaseLanguageModel"],
"category": "Chat Models",
@@ -498,7 +498,15 @@
"id": "chatOpenAI_0-input-basepath-string"
}
],
"inputAnchors": [],
"inputAnchors": [
{
"label": "Cache",
"name": "cache",
"type": "BaseCache",
"optional": true,
"id": "chatOpenAI_0-input-cache-BaseCache"
}
],
"inputs": {
"modelName": "gpt-3.5-turbo",
"temperature": 0.9,
@@ -148,14 +148,14 @@
"id": "huggingFaceInference_LLMs_0",
"position": {
"x": 498.8594464193537,
"y": -44.91050256311678
"y": -94.91050256311678
},
"type": "customNode",
"data": {
"id": "huggingFaceInference_LLMs_0",
"label": "HuggingFace Inference",
"name": "huggingFaceInference_LLMs",
"version": 1,
"version": 2,
"type": "HuggingFaceInference",
"baseClasses": ["HuggingFaceInference", "LLM", "BaseLLM", "BaseLanguageModel"],
"category": "LLMs",
@@ -232,7 +232,15 @@
"id": "huggingFaceInference_LLMs_0-input-frequencyPenalty-number"
}
],
"inputAnchors": [],
"inputAnchors": [
{
"label": "Cache",
"name": "cache",
"type": "BaseCache",
"optional": true,
"id": "huggingFaceInference_LLMs_0-input-cache-BaseCache"
}
],
"inputs": {
"model": "tiiuae/falcon-7b-instruct",
"endpoint": "",
@@ -256,7 +264,7 @@
"selected": false,
"positionAbsolute": {
"x": 498.8594464193537,
"y": -44.91050256311678
"y": -94.91050256311678
},
"dragging": false
}
@@ -265,14 +265,14 @@
"id": "chatLocalAI_0",
"position": {
"x": 1191.9512064167336,
"y": -44.05401001663306
"y": -94.05401001663306
},
"type": "customNode",
"data": {
"id": "chatLocalAI_0",
"label": "ChatLocalAI",
"name": "chatLocalAI",
"version": 1,
"version": 2,
"type": "ChatLocalAI",
"baseClasses": ["ChatLocalAI", "BaseChatModel", "LLM", "BaseLLM", "BaseLanguageModel", "BaseLangChain"],
"category": "Chat Models",
@@ -325,7 +325,15 @@
"id": "chatLocalAI_0-input-timeout-number"
}
],
"inputAnchors": [],
"inputAnchors": [
{
"label": "Cache",
"name": "cache",
"type": "BaseCache",
"optional": true,
"id": "chatLocalAI_0-input-cache-BaseCache"
}
],
"inputs": {
"basePath": "http://localhost:8080/v1",
"modelName": "ggml-gpt4all-j.bin",
@@ -348,7 +356,7 @@
"selected": false,
"positionAbsolute": {
"x": 1191.9512064167336,
"y": -44.05401001663306
"y": -94.05401001663306
},
"dragging": false
},
@@ -402,13 +410,29 @@
},
"outputAnchors": [
{
"id": "textFile_0-output-textFile-Document",
"name": "textFile",
"label": "Document",
"type": "Document"
"name": "output",
"label": "Output",
"type": "options",
"options": [
{
"id": "textFile_0-output-document-Document",
"name": "document",
"label": "Document",
"type": "Document"
},
{
"id": "textFile_0-output-text-string|json",
"name": "text",
"label": "Text",
"type": "string | json"
}
],
"default": "document"
}
],
"outputs": {},
"outputs": {
"output": "document"
},
"selected": false
},
"selected": false,
@@ -115,14 +115,14 @@
"id": "chatOpenAI_0",
"position": {
"x": 1554.3875781165111,
"y": -14.792508259787212
"y": -74.792508259787212
},
"type": "customNode",
"data": {
"id": "chatOpenAI_0",
"label": "ChatOpenAI",
"name": "chatOpenAI",
"version": 1,
"version": 2,
"type": "ChatOpenAI",
"baseClasses": ["ChatOpenAI", "BaseChatModel", "BaseLanguageModel"],
"category": "Chat Models",
@@ -234,7 +234,15 @@
"id": "chatOpenAI_0-input-basepath-string"
}
],
"inputAnchors": [],
"inputAnchors": [
{
"label": "Cache",
"name": "cache",
"type": "BaseCache",
"optional": true,
"id": "chatOpenAI_0-input-cache-BaseCache"
}
],
"inputs": {
"modelName": "gpt-3.5-turbo",
"temperature": "0",
@@ -259,7 +267,7 @@
"selected": false,
"positionAbsolute": {
"x": 1554.3875781165111,
"y": -14.792508259787212
"y": -74.792508259787212
},
"dragging": false
},
@@ -156,7 +156,7 @@
"id": "chatOpenAI_0",
"label": "ChatOpenAI",
"name": "chatOpenAI",
"version": 1,
"version": 2,
"type": "ChatOpenAI",
"baseClasses": ["ChatOpenAI", "BaseChatModel", "BaseLanguageModel"],
"category": "Chat Models",
@@ -268,7 +268,15 @@
"id": "chatOpenAI_0-input-basepath-string"
}
],
"inputAnchors": [],
"inputAnchors": [
{
"label": "Cache",
"name": "cache",
"type": "BaseCache",
"optional": true,
"id": "chatOpenAI_0-input-cache-BaseCache"
}
],
"inputs": {
"modelName": "gpt-3.5-turbo",
"temperature": 0.9,
@@ -113,14 +113,14 @@
"id": "chatOpenAI_0",
"position": {
"x": 1197.7264239788542,
"y": -16.177600120515933
"y": -76.177600120515933
},
"type": "customNode",
"data": {
"id": "chatOpenAI_0",
"label": "ChatOpenAI",
"name": "chatOpenAI",
"version": 1,
"version": 2,
"type": "ChatOpenAI",
"baseClasses": ["ChatOpenAI", "BaseChatModel", "BaseLanguageModel"],
"category": "Chat Models",
@@ -232,7 +232,15 @@
"id": "chatOpenAI_0-input-basepath-string"
}
],
"inputAnchors": [],
"inputAnchors": [
{
"label": "Cache",
"name": "cache",
"type": "BaseCache",
"optional": true,
"id": "chatOpenAI_0-input-cache-BaseCache"
}
],
"inputs": {
"modelName": "gpt-3.5-turbo",
"temperature": "0",
@@ -257,7 +265,7 @@
"selected": false,
"positionAbsolute": {
"x": 1197.7264239788542,
"y": -16.177600120515933
"y": -76.177600120515933
},
"dragging": false
},
@@ -109,13 +109,29 @@
},
"outputAnchors": [
{
"id": "textFile_0-output-textFile-Document",
"name": "textFile",
"label": "Document",
"type": "Document"
"name": "output",
"label": "Output",
"type": "options",
"options": [
{
"id": "textFile_0-output-document-Document",
"name": "document",
"label": "Document",
"type": "Document"
},
{
"id": "textFile_0-output-text-string|json",
"name": "text",
"label": "Text",
"type": "string | json"
}
],
"default": "document"
}
],
"outputs": {},
"outputs": {
"output": "document"
},
"selected": false
},
"selected": false,
@@ -436,7 +452,7 @@
"id": "chatOpenAI_0",
"label": "ChatOpenAI",
"name": "chatOpenAI",
"version": 1,
"version": 2,
"type": "ChatOpenAI",
"baseClasses": ["ChatOpenAI", "BaseChatModel", "BaseLanguageModel"],
"category": "Chat Models",
@@ -548,7 +564,15 @@
"id": "chatOpenAI_0-input-basepath-string"
}
],
"inputAnchors": [],
"inputAnchors": [
{
"label": "Cache",
"name": "cache",
"type": "BaseCache",
"optional": true,
"id": "chatOpenAI_0-input-cache-BaseCache"
}
],
"inputs": {
"modelName": "gpt-3.5-turbo",
"temperature": 0.9,
@@ -278,7 +278,7 @@
"id": "chatOpenAI_0",
"label": "ChatOpenAI",
"name": "chatOpenAI",
"version": 1,
"version": 2,
"type": "ChatOpenAI",
"baseClasses": ["ChatOpenAI", "BaseChatModel", "BaseLanguageModel"],
"category": "Chat Models",
@@ -390,7 +390,15 @@
"id": "chatOpenAI_0-input-basepath-string"
}
],
"inputAnchors": [],
"inputAnchors": [
{
"label": "Cache",
"name": "cache",
"type": "BaseCache",
"optional": true,
"id": "chatOpenAI_0-input-cache-BaseCache"
}
],
"inputs": {
"modelName": "gpt-3.5-turbo",
"temperature": 0.9,

Some files were not shown because too many files have changed in this diff Show More