@n8n/n8n-nodes-langchain 1.91.0 → 1.92.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. package/dist/credentials/AnthropicApi.credentials.js +8 -1
  2. package/dist/credentials/AnthropicApi.credentials.js.map +1 -1
  3. package/dist/credentials/AzureEntraCognitiveServicesOAuth2Api.credentials.js +150 -0
  4. package/dist/credentials/AzureEntraCognitiveServicesOAuth2Api.credentials.js.map +1 -0
  5. package/dist/known/credentials.json +10 -0
  6. package/dist/nodes/agents/Agent/agents/ToolsAgent/description.js +23 -0
  7. package/dist/nodes/agents/Agent/agents/ToolsAgent/description.js.map +1 -1
  8. package/dist/nodes/agents/Agent/agents/ToolsAgent/execute.js +28 -13
  9. package/dist/nodes/agents/Agent/agents/ToolsAgent/execute.js.map +1 -1
  10. package/dist/nodes/chains/ChainLLM/ChainLlm.node.js +39 -21
  11. package/dist/nodes/chains/ChainLLM/ChainLlm.node.js.map +1 -1
  12. package/dist/nodes/chains/ChainLLM/methods/config.js +24 -0
  13. package/dist/nodes/chains/ChainLLM/methods/config.js.map +1 -1
  14. package/dist/nodes/chains/ChainRetrievalQA/ChainRetrievalQa.node.js +55 -15
  15. package/dist/nodes/chains/ChainRetrievalQA/ChainRetrievalQa.node.js.map +1 -1
  16. package/dist/nodes/chains/ChainSummarization/V2/ChainSummarizationV2.node.js +54 -11
  17. package/dist/nodes/chains/ChainSummarization/V2/ChainSummarizationV2.node.js.map +1 -1
  18. package/dist/nodes/chains/InformationExtractor/InformationExtractor.node.js +66 -24
  19. package/dist/nodes/chains/InformationExtractor/InformationExtractor.node.js.map +1 -1
  20. package/dist/nodes/chains/SentimentAnalysis/SentimentAnalysis.node.js +86 -27
  21. package/dist/nodes/chains/SentimentAnalysis/SentimentAnalysis.node.js.map +1 -1
  22. package/dist/nodes/chains/TextClassifier/TextClassifier.node.js +81 -47
  23. package/dist/nodes/chains/TextClassifier/TextClassifier.node.js.map +1 -1
  24. package/dist/nodes/llms/LMChatAnthropic/LmChatAnthropic.node.js +5 -1
  25. package/dist/nodes/llms/LMChatAnthropic/LmChatAnthropic.node.js.map +1 -1
  26. package/dist/nodes/llms/LMChatAnthropic/methods/searchModels.js +3 -1
  27. package/dist/nodes/llms/LMChatAnthropic/methods/searchModels.js.map +1 -1
  28. package/dist/nodes/llms/LmChatAzureOpenAi/LmChatAzureOpenAi.node.js +63 -123
  29. package/dist/nodes/llms/LmChatAzureOpenAi/LmChatAzureOpenAi.node.js.map +1 -1
  30. package/dist/nodes/llms/LmChatAzureOpenAi/credentials/N8nOAuth2TokenCredential.js +61 -0
  31. package/dist/nodes/llms/LmChatAzureOpenAi/credentials/N8nOAuth2TokenCredential.js.map +1 -0
  32. package/dist/nodes/llms/LmChatAzureOpenAi/credentials/api-key.js +53 -0
  33. package/dist/nodes/llms/LmChatAzureOpenAi/credentials/api-key.js.map +1 -0
  34. package/dist/nodes/llms/LmChatAzureOpenAi/credentials/oauth2.js +54 -0
  35. package/dist/nodes/llms/LmChatAzureOpenAi/credentials/oauth2.js.map +1 -0
  36. package/dist/nodes/llms/LmChatAzureOpenAi/properties.js +155 -0
  37. package/dist/nodes/llms/LmChatAzureOpenAi/properties.js.map +1 -0
  38. package/dist/nodes/llms/LmChatAzureOpenAi/types.js +42 -0
  39. package/dist/nodes/llms/LmChatAzureOpenAi/types.js.map +1 -0
  40. package/dist/types/credentials.json +2 -1
  41. package/dist/types/nodes.json +8 -8
  42. package/package.json +8 -5
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../nodes/chains/InformationExtractor/InformationExtractor.node.ts"],"sourcesContent":["import type { BaseLanguageModel } from '@langchain/core/language_models/base';\nimport { HumanMessage } from '@langchain/core/messages';\nimport { ChatPromptTemplate, SystemMessagePromptTemplate } from '@langchain/core/prompts';\nimport type { JSONSchema7 } from 'json-schema';\nimport { OutputFixingParser, StructuredOutputParser } from 'langchain/output_parsers';\nimport { jsonParse, NodeConnectionTypes, NodeOperationError } from 'n8n-workflow';\nimport type {\n\tINodeType,\n\tINodeTypeDescription,\n\tIExecuteFunctions,\n\tINodeExecutionData,\n\tINodePropertyOptions,\n} from 'n8n-workflow';\nimport type { z } from 'zod';\n\nimport { inputSchemaField, jsonSchemaExampleField, schemaTypeField } from '@utils/descriptions';\nimport { convertJsonSchemaToZod, generateSchema } from '@utils/schemaParsing';\nimport { getTracingConfig } from '@utils/tracing';\n\nimport { makeZodSchemaFromAttributes } from './helpers';\nimport type { AttributeDefinition } from './types';\n\nconst SYSTEM_PROMPT_TEMPLATE = `You are an expert extraction algorithm.\nOnly extract relevant information from the text.\nIf you do not know the value of an attribute asked to extract, you may omit the attribute's value.`;\n\nexport class InformationExtractor implements INodeType {\n\tdescription: INodeTypeDescription = {\n\t\tdisplayName: 'Information Extractor',\n\t\tname: 'informationExtractor',\n\t\ticon: 'fa:project-diagram',\n\t\ticonColor: 'black',\n\t\tgroup: ['transform'],\n\t\tversion: 1,\n\t\tdescription: 'Extract information from text in a structured format',\n\t\tcodex: {\n\t\t\talias: ['NER', 'parse', 'parsing', 'JSON', 'data extraction', 'structured'],\n\t\t\tcategories: ['AI'],\n\t\t\tsubcategories: {\n\t\t\t\tAI: ['Chains', 'Root Nodes'],\n\t\t\t},\n\t\t\tresources: {\n\t\t\t\tprimaryDocumentation: [\n\t\t\t\t\t{\n\t\t\t\t\t\turl: 'https://docs.n8n.io/integrations/builtin/cluster-nodes/root-nodes/n8n-nodes-langchain.information-extractor/',\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t},\n\t\t},\n\t\tdefaults: {\n\t\t\tname: 'Information Extractor',\n\t\t},\n\t\tinputs: [\n\t\t\t{ displayName: '', type: NodeConnectionTypes.Main },\n\t\t\t{\n\t\t\t\tdisplayName: 'Model',\n\t\t\t\tmaxConnections: 1,\n\t\t\t\ttype: NodeConnectionTypes.AiLanguageModel,\n\t\t\t\trequired: true,\n\t\t\t},\n\t\t],\n\t\toutputs: [NodeConnectionTypes.Main],\n\t\tproperties: [\n\t\t\t{\n\t\t\t\tdisplayName: 'Text',\n\t\t\t\tname: 'text',\n\t\t\t\ttype: 'string',\n\t\t\t\tdefault: '',\n\t\t\t\tdescription: 'The text to extract information from',\n\t\t\t\ttypeOptions: {\n\t\t\t\t\trows: 2,\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\t...schemaTypeField,\n\t\t\t\tdescription: 'How to specify the schema for the desired output',\n\t\t\t\toptions: [\n\t\t\t\t\t{\n\t\t\t\t\t\tname: 'From Attribute Descriptions',\n\t\t\t\t\t\tvalue: 'fromAttributes',\n\t\t\t\t\t\tdescription:\n\t\t\t\t\t\t\t'Extract specific attributes from the text based on types and descriptions',\n\t\t\t\t\t} as INodePropertyOptions,\n\t\t\t\t\t...(schemaTypeField.options as INodePropertyOptions[]),\n\t\t\t\t],\n\t\t\t\tdefault: 'fromAttributes',\n\t\t\t},\n\t\t\t{\n\t\t\t\t...jsonSchemaExampleField,\n\t\t\t\tdefault: `{\n\t\"state\": \"California\",\n\t\"cities\": [\"Los Angeles\", \"San Francisco\", \"San Diego\"]\n}`,\n\t\t\t},\n\t\t\t{\n\t\t\t\t...inputSchemaField,\n\t\t\t\tdefault: `{\n\t\"type\": \"object\",\n\t\"properties\": {\n\t\t\"state\": {\n\t\t\t\"type\": \"string\"\n\t\t},\n\t\t\"cities\": {\n\t\t\t\"type\": \"array\",\n\t\t\t\"items\": {\n\t\t\t\t\"type\": \"string\"\n\t\t\t}\n\t\t}\n\t}\n}`,\n\t\t\t},\n\t\t\t{\n\t\t\t\tdisplayName:\n\t\t\t\t\t'The schema has to be defined in the <a target=\"_blank\" href=\"https://json-schema.org/\">JSON Schema</a> format. Look at <a target=\"_blank\" href=\"https://json-schema.org/learn/miscellaneous-examples.html\">this</a> page for examples.',\n\t\t\t\tname: 'notice',\n\t\t\t\ttype: 'notice',\n\t\t\t\tdefault: '',\n\t\t\t\tdisplayOptions: {\n\t\t\t\t\tshow: {\n\t\t\t\t\t\tschemaType: ['manual'],\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tdisplayName: 'Attributes',\n\t\t\t\tname: 'attributes',\n\t\t\t\tplaceholder: 'Add Attribute',\n\t\t\t\ttype: 'fixedCollection',\n\t\t\t\tdefault: {},\n\t\t\t\tdisplayOptions: {\n\t\t\t\t\tshow: {\n\t\t\t\t\t\tschemaType: ['fromAttributes'],\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\ttypeOptions: {\n\t\t\t\t\tmultipleValues: true,\n\t\t\t\t},\n\t\t\t\toptions: [\n\t\t\t\t\t{\n\t\t\t\t\t\tname: 'attributes',\n\t\t\t\t\t\tdisplayName: 'Attribute List',\n\t\t\t\t\t\tvalues: [\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tdisplayName: 'Name',\n\t\t\t\t\t\t\t\tname: 'name',\n\t\t\t\t\t\t\t\ttype: 'string',\n\t\t\t\t\t\t\t\tdefault: '',\n\t\t\t\t\t\t\t\tdescription: 'Attribute to extract',\n\t\t\t\t\t\t\t\tplaceholder: 'e.g. company_name',\n\t\t\t\t\t\t\t\trequired: true,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tdisplayName: 'Type',\n\t\t\t\t\t\t\t\tname: 'type',\n\t\t\t\t\t\t\t\ttype: 'options',\n\t\t\t\t\t\t\t\tdescription: 'Data type of the attribute',\n\t\t\t\t\t\t\t\trequired: true,\n\t\t\t\t\t\t\t\toptions: [\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tname: 'Boolean',\n\t\t\t\t\t\t\t\t\t\tvalue: 'boolean',\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tname: 'Date',\n\t\t\t\t\t\t\t\t\t\tvalue: 'date',\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tname: 'Number',\n\t\t\t\t\t\t\t\t\t\tvalue: 'number',\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tname: 'String',\n\t\t\t\t\t\t\t\t\t\tvalue: 'string',\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\tdefault: 'string',\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tdisplayName: 'Description',\n\t\t\t\t\t\t\t\tname: 'description',\n\t\t\t\t\t\t\t\ttype: 'string',\n\t\t\t\t\t\t\t\tdefault: '',\n\t\t\t\t\t\t\t\tdescription: 'Describe your attribute',\n\t\t\t\t\t\t\t\tplaceholder: 'Add description for the attribute',\n\t\t\t\t\t\t\t\trequired: true,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tdisplayName: 'Required',\n\t\t\t\t\t\t\t\tname: 'required',\n\t\t\t\t\t\t\t\ttype: 'boolean',\n\t\t\t\t\t\t\t\tdefault: false,\n\t\t\t\t\t\t\t\tdescription: 'Whether attribute is required',\n\t\t\t\t\t\t\t\trequired: true,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t],\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t},\n\t\t\t{\n\t\t\t\tdisplayName: 'Options',\n\t\t\t\tname: 'options',\n\t\t\t\ttype: 'collection',\n\t\t\t\tdefault: {},\n\t\t\t\tplaceholder: 'Add Option',\n\t\t\t\toptions: [\n\t\t\t\t\t{\n\t\t\t\t\t\tdisplayName: 'System Prompt Template',\n\t\t\t\t\t\tname: 'systemPromptTemplate',\n\t\t\t\t\t\ttype: 'string',\n\t\t\t\t\t\tdefault: SYSTEM_PROMPT_TEMPLATE,\n\t\t\t\t\t\tdescription: 'String to use directly as the system prompt template',\n\t\t\t\t\t\ttypeOptions: {\n\t\t\t\t\t\t\trows: 6,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t},\n\t\t],\n\t};\n\n\tasync execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]> {\n\t\tconst items = this.getInputData();\n\n\t\tconst llm = (await this.getInputConnectionData(\n\t\t\tNodeConnectionTypes.AiLanguageModel,\n\t\t\t0,\n\t\t)) as BaseLanguageModel;\n\n\t\tconst schemaType = this.getNodeParameter('schemaType', 0, '') as\n\t\t\t| 'fromAttributes'\n\t\t\t| 'fromJson'\n\t\t\t| 'manual';\n\n\t\tlet parser: OutputFixingParser<object>;\n\n\t\tif (schemaType === 'fromAttributes') {\n\t\t\tconst attributes = this.getNodeParameter(\n\t\t\t\t'attributes.attributes',\n\t\t\t\t0,\n\t\t\t\t[],\n\t\t\t) as AttributeDefinition[];\n\n\t\t\tif (attributes.length === 0) {\n\t\t\t\tthrow new NodeOperationError(this.getNode(), 'At least one attribute must be specified');\n\t\t\t}\n\n\t\t\tparser = OutputFixingParser.fromLLM(\n\t\t\t\tllm,\n\t\t\t\tStructuredOutputParser.fromZodSchema(makeZodSchemaFromAttributes(attributes)),\n\t\t\t);\n\t\t} else {\n\t\t\tlet jsonSchema: JSONSchema7;\n\n\t\t\tif (schemaType === 'fromJson') {\n\t\t\t\tconst jsonExample = this.getNodeParameter('jsonSchemaExample', 0, '') as string;\n\t\t\t\tjsonSchema = generateSchema(jsonExample);\n\t\t\t} else {\n\t\t\t\tconst inputSchema = this.getNodeParameter('inputSchema', 0, '') as string;\n\t\t\t\tjsonSchema = jsonParse<JSONSchema7>(inputSchema);\n\t\t\t}\n\n\t\t\tconst zodSchema = convertJsonSchemaToZod<z.ZodSchema<object>>(jsonSchema);\n\n\t\t\tparser = OutputFixingParser.fromLLM(llm, StructuredOutputParser.fromZodSchema(zodSchema));\n\t\t}\n\n\t\tconst resultData: INodeExecutionData[] = [];\n\t\tfor (let itemIndex = 0; itemIndex < items.length; itemIndex++) {\n\t\t\tconst input = this.getNodeParameter('text', itemIndex) as string;\n\t\t\tconst inputPrompt = new HumanMessage(input);\n\n\t\t\tconst options = this.getNodeParameter('options', itemIndex, {}) as {\n\t\t\t\tsystemPromptTemplate?: string;\n\t\t\t};\n\n\t\t\tconst systemPromptTemplate = SystemMessagePromptTemplate.fromTemplate(\n\t\t\t\t`${options.systemPromptTemplate ?? SYSTEM_PROMPT_TEMPLATE}\n{format_instructions}`,\n\t\t\t);\n\n\t\t\tconst messages = [\n\t\t\t\tawait systemPromptTemplate.format({\n\t\t\t\t\tformat_instructions: parser.getFormatInstructions(),\n\t\t\t\t}),\n\t\t\t\tinputPrompt,\n\t\t\t];\n\t\t\tconst prompt = ChatPromptTemplate.fromMessages(messages);\n\t\t\tconst chain = prompt.pipe(llm).pipe(parser).withConfig(getTracingConfig(this));\n\n\t\t\ttry {\n\t\t\t\tconst output = await chain.invoke(messages);\n\t\t\t\tresultData.push({ json: { output } });\n\t\t\t} catch (error) {\n\t\t\t\tif (this.continueOnFail()) {\n\t\t\t\t\tresultData.push({ json: { error: error.message }, pairedItem: { item: itemIndex } });\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t}\n\n\t\treturn [resultData];\n\t}\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../../../nodes/chains/InformationExtractor/InformationExtractor.node.ts"],"sourcesContent":["import type { BaseLanguageModel } from '@langchain/core/language_models/base';\nimport { HumanMessage } from '@langchain/core/messages';\nimport { ChatPromptTemplate, SystemMessagePromptTemplate } from '@langchain/core/prompts';\nimport type { JSONSchema7 } from 'json-schema';\nimport { OutputFixingParser, StructuredOutputParser } from 'langchain/output_parsers';\nimport { jsonParse, NodeConnectionTypes, NodeOperationError, sleep } from 'n8n-workflow';\nimport type {\n\tINodeType,\n\tINodeTypeDescription,\n\tIExecuteFunctions,\n\tINodeExecutionData,\n\tINodePropertyOptions,\n} from 'n8n-workflow';\nimport type { z } from 'zod';\n\nimport { inputSchemaField, jsonSchemaExampleField, schemaTypeField } from '@utils/descriptions';\nimport { convertJsonSchemaToZod, generateSchema } from '@utils/schemaParsing';\nimport { getTracingConfig } from '@utils/tracing';\n\nimport { makeZodSchemaFromAttributes } from './helpers';\nimport type { AttributeDefinition } from './types';\n\nconst SYSTEM_PROMPT_TEMPLATE = `You are an expert extraction algorithm.\nOnly extract relevant information from the text.\nIf you do not know the value of an attribute asked to extract, you may omit the attribute's value.`;\n\nexport class InformationExtractor implements INodeType {\n\tdescription: INodeTypeDescription = {\n\t\tdisplayName: 'Information Extractor',\n\t\tname: 'informationExtractor',\n\t\ticon: 'fa:project-diagram',\n\t\ticonColor: 'black',\n\t\tgroup: ['transform'],\n\t\tversion: 1,\n\t\tdescription: 'Extract information from text in a structured format',\n\t\tcodex: {\n\t\t\talias: ['NER', 'parse', 'parsing', 'JSON', 'data extraction', 'structured'],\n\t\t\tcategories: ['AI'],\n\t\t\tsubcategories: {\n\t\t\t\tAI: ['Chains', 'Root Nodes'],\n\t\t\t},\n\t\t\tresources: {\n\t\t\t\tprimaryDocumentation: [\n\t\t\t\t\t{\n\t\t\t\t\t\turl: 'https://docs.n8n.io/integrations/builtin/cluster-nodes/root-nodes/n8n-nodes-langchain.information-extractor/',\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t},\n\t\t},\n\t\tdefaults: {\n\t\t\tname: 'Information Extractor',\n\t\t},\n\t\tinputs: [\n\t\t\t{ displayName: '', type: NodeConnectionTypes.Main },\n\t\t\t{\n\t\t\t\tdisplayName: 'Model',\n\t\t\t\tmaxConnections: 1,\n\t\t\t\ttype: NodeConnectionTypes.AiLanguageModel,\n\t\t\t\trequired: true,\n\t\t\t},\n\t\t],\n\t\toutputs: [NodeConnectionTypes.Main],\n\t\tproperties: [\n\t\t\t{\n\t\t\t\tdisplayName: 'Text',\n\t\t\t\tname: 'text',\n\t\t\t\ttype: 'string',\n\t\t\t\tdefault: '',\n\t\t\t\tdescription: 'The text to extract information from',\n\t\t\t\ttypeOptions: {\n\t\t\t\t\trows: 2,\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\t...schemaTypeField,\n\t\t\t\tdescription: 'How to specify the schema for the desired output',\n\t\t\t\toptions: [\n\t\t\t\t\t{\n\t\t\t\t\t\tname: 'From Attribute Descriptions',\n\t\t\t\t\t\tvalue: 'fromAttributes',\n\t\t\t\t\t\tdescription:\n\t\t\t\t\t\t\t'Extract specific attributes from the text based on types and descriptions',\n\t\t\t\t\t} as INodePropertyOptions,\n\t\t\t\t\t...(schemaTypeField.options as INodePropertyOptions[]),\n\t\t\t\t],\n\t\t\t\tdefault: 'fromAttributes',\n\t\t\t},\n\t\t\t{\n\t\t\t\t...jsonSchemaExampleField,\n\t\t\t\tdefault: `{\n\t\"state\": \"California\",\n\t\"cities\": [\"Los Angeles\", \"San Francisco\", \"San Diego\"]\n}`,\n\t\t\t},\n\t\t\t{\n\t\t\t\t...inputSchemaField,\n\t\t\t\tdefault: `{\n\t\"type\": \"object\",\n\t\"properties\": {\n\t\t\"state\": {\n\t\t\t\"type\": \"string\"\n\t\t},\n\t\t\"cities\": {\n\t\t\t\"type\": \"array\",\n\t\t\t\"items\": {\n\t\t\t\t\"type\": \"string\"\n\t\t\t}\n\t\t}\n\t}\n}`,\n\t\t\t},\n\t\t\t{\n\t\t\t\tdisplayName:\n\t\t\t\t\t'The schema has to be defined in the <a target=\"_blank\" href=\"https://json-schema.org/\">JSON Schema</a> format. Look at <a target=\"_blank\" href=\"https://json-schema.org/learn/miscellaneous-examples.html\">this</a> page for examples.',\n\t\t\t\tname: 'notice',\n\t\t\t\ttype: 'notice',\n\t\t\t\tdefault: '',\n\t\t\t\tdisplayOptions: {\n\t\t\t\t\tshow: {\n\t\t\t\t\t\tschemaType: ['manual'],\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tdisplayName: 'Attributes',\n\t\t\t\tname: 'attributes',\n\t\t\t\tplaceholder: 'Add Attribute',\n\t\t\t\ttype: 'fixedCollection',\n\t\t\t\tdefault: {},\n\t\t\t\tdisplayOptions: {\n\t\t\t\t\tshow: {\n\t\t\t\t\t\tschemaType: ['fromAttributes'],\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\ttypeOptions: {\n\t\t\t\t\tmultipleValues: true,\n\t\t\t\t},\n\t\t\t\toptions: [\n\t\t\t\t\t{\n\t\t\t\t\t\tname: 'attributes',\n\t\t\t\t\t\tdisplayName: 'Attribute List',\n\t\t\t\t\t\tvalues: [\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tdisplayName: 'Name',\n\t\t\t\t\t\t\t\tname: 'name',\n\t\t\t\t\t\t\t\ttype: 'string',\n\t\t\t\t\t\t\t\tdefault: '',\n\t\t\t\t\t\t\t\tdescription: 'Attribute to extract',\n\t\t\t\t\t\t\t\tplaceholder: 'e.g. company_name',\n\t\t\t\t\t\t\t\trequired: true,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tdisplayName: 'Type',\n\t\t\t\t\t\t\t\tname: 'type',\n\t\t\t\t\t\t\t\ttype: 'options',\n\t\t\t\t\t\t\t\tdescription: 'Data type of the attribute',\n\t\t\t\t\t\t\t\trequired: true,\n\t\t\t\t\t\t\t\toptions: [\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tname: 'Boolean',\n\t\t\t\t\t\t\t\t\t\tvalue: 'boolean',\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tname: 'Date',\n\t\t\t\t\t\t\t\t\t\tvalue: 'date',\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tname: 'Number',\n\t\t\t\t\t\t\t\t\t\tvalue: 'number',\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tname: 'String',\n\t\t\t\t\t\t\t\t\t\tvalue: 'string',\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\tdefault: 'string',\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tdisplayName: 'Description',\n\t\t\t\t\t\t\t\tname: 'description',\n\t\t\t\t\t\t\t\ttype: 'string',\n\t\t\t\t\t\t\t\tdefault: '',\n\t\t\t\t\t\t\t\tdescription: 'Describe your attribute',\n\t\t\t\t\t\t\t\tplaceholder: 'Add description for the attribute',\n\t\t\t\t\t\t\t\trequired: true,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tdisplayName: 'Required',\n\t\t\t\t\t\t\t\tname: 'required',\n\t\t\t\t\t\t\t\ttype: 'boolean',\n\t\t\t\t\t\t\t\tdefault: false,\n\t\t\t\t\t\t\t\tdescription: 'Whether attribute is required',\n\t\t\t\t\t\t\t\trequired: true,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t],\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t},\n\t\t\t{\n\t\t\t\tdisplayName: 'Options',\n\t\t\t\tname: 'options',\n\t\t\t\ttype: 'collection',\n\t\t\t\tdefault: {},\n\t\t\t\tplaceholder: 'Add Option',\n\t\t\t\toptions: [\n\t\t\t\t\t{\n\t\t\t\t\t\tdisplayName: 'System Prompt Template',\n\t\t\t\t\t\tname: 'systemPromptTemplate',\n\t\t\t\t\t\ttype: 'string',\n\t\t\t\t\t\tdefault: SYSTEM_PROMPT_TEMPLATE,\n\t\t\t\t\t\tdescription: 'String to use directly as the system prompt template',\n\t\t\t\t\t\ttypeOptions: {\n\t\t\t\t\t\t\trows: 6,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tdisplayName: 'Batch Processing',\n\t\t\t\t\t\tname: 'batching',\n\t\t\t\t\t\ttype: 'collection',\n\t\t\t\t\t\tdescription: 'Batch processing options for rate limiting',\n\t\t\t\t\t\tdefault: {},\n\t\t\t\t\t\toptions: [\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tdisplayName: 'Batch Size',\n\t\t\t\t\t\t\t\tname: 'batchSize',\n\t\t\t\t\t\t\t\tdefault: 100,\n\t\t\t\t\t\t\t\ttype: 'number',\n\t\t\t\t\t\t\t\tdescription:\n\t\t\t\t\t\t\t\t\t'How many items to process in parallel. This is useful for rate limiting, but will impact the agents log output.',\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tdisplayName: 'Delay Between Batches',\n\t\t\t\t\t\t\t\tname: 'delayBetweenBatches',\n\t\t\t\t\t\t\t\tdefault: 0,\n\t\t\t\t\t\t\t\ttype: 'number',\n\t\t\t\t\t\t\t\tdescription:\n\t\t\t\t\t\t\t\t\t'Delay in milliseconds between batches. This is useful for rate limiting.',\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t],\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t},\n\t\t],\n\t};\n\n\tasync execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]> {\n\t\tconst items = this.getInputData();\n\t\tconst { batchSize, delayBetweenBatches } = this.getNodeParameter('options.batching', 0, {\n\t\t\tbatchSize: 100,\n\t\t\tdelayBetweenBatches: 0,\n\t\t}) as {\n\t\t\tbatchSize: number;\n\t\t\tdelayBetweenBatches: number;\n\t\t};\n\n\t\tconst llm = (await this.getInputConnectionData(\n\t\t\tNodeConnectionTypes.AiLanguageModel,\n\t\t\t0,\n\t\t)) as BaseLanguageModel;\n\n\t\tconst schemaType = this.getNodeParameter('schemaType', 0, '') as\n\t\t\t| 'fromAttributes'\n\t\t\t| 'fromJson'\n\t\t\t| 'manual';\n\n\t\tlet parser: OutputFixingParser<object>;\n\n\t\tif (schemaType === 'fromAttributes') {\n\t\t\tconst attributes = this.getNodeParameter(\n\t\t\t\t'attributes.attributes',\n\t\t\t\t0,\n\t\t\t\t[],\n\t\t\t) as AttributeDefinition[];\n\n\t\t\tif (attributes.length === 0) {\n\t\t\t\tthrow new NodeOperationError(this.getNode(), 'At least one attribute must be specified');\n\t\t\t}\n\n\t\t\tparser = OutputFixingParser.fromLLM(\n\t\t\t\tllm,\n\t\t\t\tStructuredOutputParser.fromZodSchema(makeZodSchemaFromAttributes(attributes)),\n\t\t\t);\n\t\t} else {\n\t\t\tlet jsonSchema: JSONSchema7;\n\n\t\t\tif (schemaType === 'fromJson') {\n\t\t\t\tconst jsonExample = this.getNodeParameter('jsonSchemaExample', 0, '') as string;\n\t\t\t\tjsonSchema = generateSchema(jsonExample);\n\t\t\t} else {\n\t\t\t\tconst inputSchema = this.getNodeParameter('inputSchema', 0, '') as string;\n\t\t\t\tjsonSchema = jsonParse<JSONSchema7>(inputSchema);\n\t\t\t}\n\n\t\t\tconst zodSchema = convertJsonSchemaToZod<z.ZodSchema<object>>(jsonSchema);\n\n\t\t\tparser = OutputFixingParser.fromLLM(llm, StructuredOutputParser.fromZodSchema(zodSchema));\n\t\t}\n\n\t\tconst resultData: INodeExecutionData[] = [];\n\n\t\tfor (let i = 0; i < items.length; i += batchSize) {\n\t\t\tconst batch = items.slice(i, i + batchSize);\n\n\t\t\tconst batchPromises = batch.map(async (_item, batchItemIndex) => {\n\t\t\t\tconst itemIndex = i + batchItemIndex;\n\n\t\t\t\tconst input = this.getNodeParameter('text', itemIndex) as string;\n\t\t\t\tconst inputPrompt = new HumanMessage(input);\n\n\t\t\t\tconst options = this.getNodeParameter('options', itemIndex, {}) as {\n\t\t\t\t\tsystemPromptTemplate?: string;\n\t\t\t\t};\n\n\t\t\t\tconst systemPromptTemplate = SystemMessagePromptTemplate.fromTemplate(\n\t\t\t\t\t`${options.systemPromptTemplate ?? SYSTEM_PROMPT_TEMPLATE}\n\t{format_instructions}`,\n\t\t\t\t);\n\n\t\t\t\tconst messages = [\n\t\t\t\t\tawait systemPromptTemplate.format({\n\t\t\t\t\t\tformat_instructions: parser.getFormatInstructions(),\n\t\t\t\t\t}),\n\t\t\t\t\tinputPrompt,\n\t\t\t\t];\n\t\t\t\tconst prompt = ChatPromptTemplate.fromMessages(messages);\n\t\t\t\tconst chain = prompt.pipe(llm).pipe(parser).withConfig(getTracingConfig(this));\n\n\t\t\t\treturn await chain.invoke(messages);\n\t\t\t});\n\t\t\tconst batchResults = await Promise.allSettled(batchPromises);\n\n\t\t\tbatchResults.forEach((response, index) => {\n\t\t\t\tif (response.status === 'rejected') {\n\t\t\t\t\tconst error = response.reason as Error;\n\t\t\t\t\tif (this.continueOnFail()) {\n\t\t\t\t\t\tresultData.push({\n\t\t\t\t\t\t\tjson: { error: response.reason as string },\n\t\t\t\t\t\t\tpairedItem: { item: i + index },\n\t\t\t\t\t\t});\n\t\t\t\t\t\treturn;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tthrow new NodeOperationError(this.getNode(), error.message);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tconst output = response.value;\n\t\t\t\tresultData.push({ json: { output } });\n\t\t\t});\n\n\t\t\t// Add delay between batches if not the last batch\n\t\t\tif (i + batchSize < items.length && delayBetweenBatches > 0) {\n\t\t\t\tawait sleep(delayBetweenBatches);\n\t\t\t}\n\t\t}\n\n\t\treturn [resultData];\n\t}\n}\n"],"mappings":"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","names":[]}
@@ -136,6 +136,29 @@ class SentimentAnalysis {
136
136
  type: "boolean",
137
137
  default: true,
138
138
  description: "Whether to enable auto-fixing (may trigger an additional LLM call if output is broken)"
139
+ },
140
+ {
141
+ displayName: "Batch Processing",
142
+ name: "batching",
143
+ type: "collection",
144
+ description: "Batch processing options for rate limiting",
145
+ default: {},
146
+ options: [
147
+ {
148
+ displayName: "Batch Size",
149
+ name: "batchSize",
150
+ default: 100,
151
+ type: "number",
152
+ description: "How many items to process in parallel. This is useful for rate limiting."
153
+ },
154
+ {
155
+ displayName: "Delay Between Batches",
156
+ name: "delayBetweenBatches",
157
+ default: 0,
158
+ type: "number",
159
+ description: "Delay in milliseconds between batches. This is useful for rate limiting."
160
+ }
161
+ ]
139
162
  }
140
163
  ]
141
164
  }
@@ -149,23 +172,33 @@ class SentimentAnalysis {
149
172
  0
150
173
  );
151
174
  const returnData = [];
152
- for (let i = 0; i < items.length; i++) {
153
- try {
175
+ const { batchSize, delayBetweenBatches } = this.getNodeParameter("options.batching", 0, {
176
+ batchSize: 100,
177
+ delayBetweenBatches: 0
178
+ });
179
+ for (let i = 0; i < items.length; i += batchSize) {
180
+ const batch = items.slice(i, i + batchSize);
181
+ const batchPromises = batch.map(async (_item, batchItemIndex) => {
182
+ const itemIndex = i + batchItemIndex;
154
183
  const sentimentCategories = this.getNodeParameter(
155
184
  "options.categories",
156
- i,
185
+ itemIndex,
157
186
  DEFAULT_CATEGORIES
158
187
  );
159
188
  const categories = sentimentCategories.split(",").map((cat) => cat.trim()).filter(Boolean);
160
189
  if (categories.length === 0) {
161
- throw new import_n8n_workflow.NodeOperationError(this.getNode(), "No sentiment categories provided", {
162
- itemIndex: i
163
- });
190
+ return {
191
+ result: null,
192
+ itemIndex,
193
+ error: new import_n8n_workflow.NodeOperationError(this.getNode(), "No sentiment categories provided", {
194
+ itemIndex
195
+ })
196
+ };
164
197
  }
165
198
  if (returnData.length === 0) {
166
199
  returnData.push(...Array.from({ length: categories.length }, () => []));
167
200
  }
168
- const options = this.getNodeParameter("options", i, {});
201
+ const options = this.getNodeParameter("options", itemIndex, {});
169
202
  const schema = import_zod.z.object({
170
203
  sentiment: import_zod.z.enum(categories),
171
204
  strength: import_zod.z.number().min(0).max(1).describe("Strength score for sentiment in relation to the category"),
@@ -175,9 +208,9 @@ class SentimentAnalysis {
175
208
  const parser = options.enableAutoFixing ? import_output_parsers.OutputFixingParser.fromLLM(llm, structuredParser) : structuredParser;
176
209
  const systemPromptTemplate = import_prompts.SystemMessagePromptTemplate.fromTemplate(
177
210
  `${options.systemPromptTemplate ?? DEFAULT_SYSTEM_PROMPT_TEMPLATE}
178
- {format_instructions}`
211
+ {format_instructions}`
179
212
  );
180
- const input = this.getNodeParameter("inputText", i);
213
+ const input = this.getNodeParameter("inputText", itemIndex);
181
214
  const inputPrompt = new import_messages.HumanMessage(input);
182
215
  const messages = [
183
216
  await systemPromptTemplate.format({
@@ -194,7 +227,7 @@ class SentimentAnalysis {
194
227
  (s) => s.toLowerCase() === output.sentiment.toLowerCase()
195
228
  );
196
229
  if (sentimentIndex !== -1) {
197
- const resultItem = { ...items[i] };
230
+ const resultItem = { ...items[itemIndex] };
198
231
  const sentimentAnalysis = {
199
232
  category: output.sentiment
200
233
  };
@@ -206,27 +239,53 @@ class SentimentAnalysis {
206
239
  ...resultItem.json,
207
240
  sentimentAnalysis
208
241
  };
209
- returnData[sentimentIndex].push(resultItem);
242
+ return {
243
+ result: {
244
+ resultItem,
245
+ sentimentIndex
246
+ },
247
+ itemIndex
248
+ };
210
249
  }
250
+ return {
251
+ result: {},
252
+ itemIndex
253
+ };
211
254
  } catch (error) {
212
- throw new import_n8n_workflow.NodeOperationError(
213
- this.getNode(),
214
- "Error during parsing of LLM output, please check your LLM model and configuration",
215
- {
216
- itemIndex: i
217
- }
218
- );
255
+ return {
256
+ result: null,
257
+ itemIndex,
258
+ error: new import_n8n_workflow.NodeOperationError(
259
+ this.getNode(),
260
+ "Error during parsing of LLM output, please check your LLM model and configuration",
261
+ {
262
+ itemIndex
263
+ }
264
+ )
265
+ };
219
266
  }
220
- } catch (error) {
221
- if (this.continueOnFail()) {
222
- const executionErrorData = this.helpers.constructExecutionMetaData(
223
- this.helpers.returnJsonArray({ error: error.message }),
224
- { itemData: { item: i } }
225
- );
226
- returnData[0].push(...executionErrorData);
227
- continue;
267
+ });
268
+ const batchResults = await Promise.all(batchPromises);
269
+ batchResults.forEach(({ result, itemIndex, error }) => {
270
+ if (error) {
271
+ if (this.continueOnFail()) {
272
+ const executionErrorData = this.helpers.constructExecutionMetaData(
273
+ this.helpers.returnJsonArray({ error: error.message }),
274
+ { itemData: { item: itemIndex } }
275
+ );
276
+ returnData[0].push(...executionErrorData);
277
+ return;
278
+ } else {
279
+ throw error;
280
+ }
281
+ } else if (result.resultItem && result.sentimentIndex) {
282
+ const sentimentIndex = result.sentimentIndex;
283
+ const resultItem = result.resultItem;
284
+ returnData[sentimentIndex].push(resultItem);
228
285
  }
229
- throw error;
286
+ });
287
+ if (i + batchSize < items.length && delayBetweenBatches > 0) {
288
+ await (0, import_n8n_workflow.sleep)(delayBetweenBatches);
230
289
  }
231
290
  }
232
291
  return returnData;
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../nodes/chains/SentimentAnalysis/SentimentAnalysis.node.ts"],"sourcesContent":["import type { BaseLanguageModel } from '@langchain/core/language_models/base';\nimport { HumanMessage } from '@langchain/core/messages';\nimport { SystemMessagePromptTemplate, ChatPromptTemplate } from '@langchain/core/prompts';\nimport { OutputFixingParser, StructuredOutputParser } from 'langchain/output_parsers';\nimport { NodeConnectionTypes, NodeOperationError } from 'n8n-workflow';\nimport type {\n\tIDataObject,\n\tIExecuteFunctions,\n\tINodeExecutionData,\n\tINodeParameters,\n\tINodeType,\n\tINodeTypeDescription,\n} from 'n8n-workflow';\nimport { z } from 'zod';\n\nimport { getTracingConfig } from '@utils/tracing';\n\nconst DEFAULT_SYSTEM_PROMPT_TEMPLATE =\n\t'You are highly intelligent and accurate sentiment analyzer. Analyze the sentiment of the provided text. Categorize it into one of the following: {categories}. Use the provided formatting instructions. Only output the JSON.';\n\nconst DEFAULT_CATEGORIES = 'Positive, Neutral, Negative';\nconst configuredOutputs = (parameters: INodeParameters, defaultCategories: string) => {\n\tconst options = (parameters?.options ?? {}) as IDataObject;\n\tconst categories = (options?.categories as string) ?? defaultCategories;\n\tconst categoriesArray = categories.split(',').map((cat) => cat.trim());\n\n\tconst ret = categoriesArray.map((cat) => ({ type: 'main', displayName: cat }));\n\treturn ret;\n};\n\nexport class SentimentAnalysis implements INodeType {\n\tdescription: INodeTypeDescription = {\n\t\tdisplayName: 'Sentiment Analysis',\n\t\tname: 'sentimentAnalysis',\n\t\ticon: 'fa:balance-scale-left',\n\t\ticonColor: 'black',\n\t\tgroup: ['transform'],\n\t\tversion: 1,\n\t\tdescription: 'Analyze the sentiment of your text',\n\t\tcodex: {\n\t\t\tcategories: ['AI'],\n\t\t\tsubcategories: {\n\t\t\t\tAI: ['Chains', 'Root Nodes'],\n\t\t\t},\n\t\t\tresources: {\n\t\t\t\tprimaryDocumentation: [\n\t\t\t\t\t{\n\t\t\t\t\t\turl: 'https://docs.n8n.io/integrations/builtin/cluster-nodes/root-nodes/n8n-nodes-langchain.sentimentanalysis/',\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t},\n\t\t},\n\t\tdefaults: {\n\t\t\tname: 'Sentiment Analysis',\n\t\t},\n\t\tinputs: [\n\t\t\t{ displayName: '', type: NodeConnectionTypes.Main },\n\t\t\t{\n\t\t\t\tdisplayName: 'Model',\n\t\t\t\tmaxConnections: 1,\n\t\t\t\ttype: NodeConnectionTypes.AiLanguageModel,\n\t\t\t\trequired: true,\n\t\t\t},\n\t\t],\n\t\toutputs: `={{(${configuredOutputs})($parameter, \"${DEFAULT_CATEGORIES}\")}}`,\n\t\tproperties: [\n\t\t\t{\n\t\t\t\tdisplayName: 'Text to Analyze',\n\t\t\t\tname: 'inputText',\n\t\t\t\ttype: 'string',\n\t\t\t\trequired: true,\n\t\t\t\tdefault: '',\n\t\t\t\tdescription: 'Use an expression to reference data in previous nodes or enter static text',\n\t\t\t\ttypeOptions: {\n\t\t\t\t\trows: 2,\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tdisplayName:\n\t\t\t\t\t'Sentiment scores are LLM-generated estimates, not statistically rigorous measurements. They may be inconsistent across runs and should be used as rough indicators only.',\n\t\t\t\tname: 'detailedResultsNotice',\n\t\t\t\ttype: 'notice',\n\t\t\t\tdefault: '',\n\t\t\t\tdisplayOptions: {\n\t\t\t\t\tshow: {\n\t\t\t\t\t\t'/options.includeDetailedResults': [true],\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tdisplayName: 'Options',\n\t\t\t\tname: 'options',\n\t\t\t\ttype: 'collection',\n\t\t\t\tdefault: {},\n\t\t\t\tplaceholder: 'Add Option',\n\t\t\t\toptions: [\n\t\t\t\t\t{\n\t\t\t\t\t\tdisplayName: 'Sentiment Categories',\n\t\t\t\t\t\tname: 'categories',\n\t\t\t\t\t\ttype: 'string',\n\t\t\t\t\t\tdefault: DEFAULT_CATEGORIES,\n\t\t\t\t\t\tdescription: 'A comma-separated list of categories to analyze',\n\t\t\t\t\t\tnoDataExpression: true,\n\t\t\t\t\t\ttypeOptions: {\n\t\t\t\t\t\t\trows: 2,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tdisplayName: 'System Prompt Template',\n\t\t\t\t\t\tname: 'systemPromptTemplate',\n\t\t\t\t\t\ttype: 'string',\n\t\t\t\t\t\tdefault: DEFAULT_SYSTEM_PROMPT_TEMPLATE,\n\t\t\t\t\t\tdescription: 'String to use directly as the system prompt template',\n\t\t\t\t\t\ttypeOptions: {\n\t\t\t\t\t\t\trows: 6,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tdisplayName: 'Include Detailed Results',\n\t\t\t\t\t\tname: 'includeDetailedResults',\n\t\t\t\t\t\ttype: 'boolean',\n\t\t\t\t\t\tdefault: false,\n\t\t\t\t\t\tdescription:\n\t\t\t\t\t\t\t'Whether to include sentiment strength and confidence scores in the output',\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tdisplayName: 'Enable Auto-Fixing',\n\t\t\t\t\t\tname: 'enableAutoFixing',\n\t\t\t\t\t\ttype: 'boolean',\n\t\t\t\t\t\tdefault: true,\n\t\t\t\t\t\tdescription:\n\t\t\t\t\t\t\t'Whether to enable auto-fixing (may trigger an additional LLM call if output is broken)',\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t},\n\t\t],\n\t};\n\n\tasync execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]> {\n\t\tconst items = this.getInputData();\n\n\t\tconst llm = (await this.getInputConnectionData(\n\t\t\tNodeConnectionTypes.AiLanguageModel,\n\t\t\t0,\n\t\t)) as BaseLanguageModel;\n\n\t\tconst returnData: INodeExecutionData[][] = [];\n\n\t\tfor (let i = 0; i < items.length; i++) {\n\t\t\ttry {\n\t\t\t\tconst sentimentCategories = this.getNodeParameter(\n\t\t\t\t\t'options.categories',\n\t\t\t\t\ti,\n\t\t\t\t\tDEFAULT_CATEGORIES,\n\t\t\t\t) as string;\n\n\t\t\t\tconst categories = sentimentCategories\n\t\t\t\t\t.split(',')\n\t\t\t\t\t.map((cat) => cat.trim())\n\t\t\t\t\t.filter(Boolean);\n\n\t\t\t\tif (categories.length === 0) {\n\t\t\t\t\tthrow new NodeOperationError(this.getNode(), 'No sentiment categories provided', {\n\t\t\t\t\t\titemIndex: i,\n\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\t// Initialize returnData with empty arrays for each category\n\t\t\t\tif (returnData.length === 0) {\n\t\t\t\t\treturnData.push(...Array.from({ length: categories.length }, () => []));\n\t\t\t\t}\n\n\t\t\t\tconst options = this.getNodeParameter('options', i, {}) as {\n\t\t\t\t\tsystemPromptTemplate?: string;\n\t\t\t\t\tincludeDetailedResults?: boolean;\n\t\t\t\t\tenableAutoFixing?: boolean;\n\t\t\t\t};\n\n\t\t\t\tconst schema = z.object({\n\t\t\t\t\tsentiment: z.enum(categories as [string, ...string[]]),\n\t\t\t\t\tstrength: z\n\t\t\t\t\t\t.number()\n\t\t\t\t\t\t.min(0)\n\t\t\t\t\t\t.max(1)\n\t\t\t\t\t\t.describe('Strength score for sentiment in relation to the category'),\n\t\t\t\t\tconfidence: z.number().min(0).max(1),\n\t\t\t\t});\n\n\t\t\t\tconst structuredParser = StructuredOutputParser.fromZodSchema(schema);\n\n\t\t\t\tconst parser = options.enableAutoFixing\n\t\t\t\t\t? OutputFixingParser.fromLLM(llm, structuredParser)\n\t\t\t\t\t: structuredParser;\n\n\t\t\t\tconst systemPromptTemplate = SystemMessagePromptTemplate.fromTemplate(\n\t\t\t\t\t`${options.systemPromptTemplate ?? DEFAULT_SYSTEM_PROMPT_TEMPLATE}\n\t\t{format_instructions}`,\n\t\t\t\t);\n\n\t\t\t\tconst input = this.getNodeParameter('inputText', i) as string;\n\t\t\t\tconst inputPrompt = new HumanMessage(input);\n\t\t\t\tconst messages = [\n\t\t\t\t\tawait systemPromptTemplate.format({\n\t\t\t\t\t\tcategories: sentimentCategories,\n\t\t\t\t\t\tformat_instructions: parser.getFormatInstructions(),\n\t\t\t\t\t}),\n\t\t\t\t\tinputPrompt,\n\t\t\t\t];\n\n\t\t\t\tconst prompt = ChatPromptTemplate.fromMessages(messages);\n\t\t\t\tconst chain = prompt.pipe(llm).pipe(parser).withConfig(getTracingConfig(this));\n\n\t\t\t\ttry {\n\t\t\t\t\tconst output = await chain.invoke(messages);\n\t\t\t\t\tconst sentimentIndex = categories.findIndex(\n\t\t\t\t\t\t(s) => s.toLowerCase() === output.sentiment.toLowerCase(),\n\t\t\t\t\t);\n\n\t\t\t\t\tif (sentimentIndex !== -1) {\n\t\t\t\t\t\tconst resultItem = { ...items[i] };\n\t\t\t\t\t\tconst sentimentAnalysis: IDataObject = {\n\t\t\t\t\t\t\tcategory: output.sentiment,\n\t\t\t\t\t\t};\n\t\t\t\t\t\tif (options.includeDetailedResults) {\n\t\t\t\t\t\t\tsentimentAnalysis.strength = output.strength;\n\t\t\t\t\t\t\tsentimentAnalysis.confidence = output.confidence;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tresultItem.json = {\n\t\t\t\t\t\t\t...resultItem.json,\n\t\t\t\t\t\t\tsentimentAnalysis,\n\t\t\t\t\t\t};\n\t\t\t\t\t\treturnData[sentimentIndex].push(resultItem);\n\t\t\t\t\t}\n\t\t\t\t} catch (error) {\n\t\t\t\t\tthrow new NodeOperationError(\n\t\t\t\t\t\tthis.getNode(),\n\t\t\t\t\t\t'Error during parsing of LLM output, please check your LLM model and configuration',\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\titemIndex: i,\n\t\t\t\t\t\t},\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t} catch (error) {\n\t\t\t\tif (this.continueOnFail()) {\n\t\t\t\t\tconst executionErrorData = this.helpers.constructExecutionMetaData(\n\t\t\t\t\t\tthis.helpers.returnJsonArray({ error: error.message }),\n\t\t\t\t\t\t{ itemData: { item: i } },\n\t\t\t\t\t);\n\t\t\t\t\treturnData[0].push(...executionErrorData);\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t}\n\t\treturn returnData;\n\t}\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../../../nodes/chains/SentimentAnalysis/SentimentAnalysis.node.ts"],"sourcesContent":["import type { BaseLanguageModel } from '@langchain/core/language_models/base';\nimport { HumanMessage } from '@langchain/core/messages';\nimport { SystemMessagePromptTemplate, ChatPromptTemplate } from '@langchain/core/prompts';\nimport { OutputFixingParser, StructuredOutputParser } from 'langchain/output_parsers';\nimport { NodeConnectionTypes, NodeOperationError, sleep } from 'n8n-workflow';\nimport type {\n\tIDataObject,\n\tIExecuteFunctions,\n\tINodeExecutionData,\n\tINodeParameters,\n\tINodeType,\n\tINodeTypeDescription,\n} from 'n8n-workflow';\nimport { z } from 'zod';\n\nimport { getTracingConfig } from '@utils/tracing';\n\nconst DEFAULT_SYSTEM_PROMPT_TEMPLATE =\n\t'You are highly intelligent and accurate sentiment analyzer. Analyze the sentiment of the provided text. Categorize it into one of the following: {categories}. Use the provided formatting instructions. Only output the JSON.';\n\nconst DEFAULT_CATEGORIES = 'Positive, Neutral, Negative';\nconst configuredOutputs = (parameters: INodeParameters, defaultCategories: string) => {\n\tconst options = (parameters?.options ?? {}) as IDataObject;\n\tconst categories = (options?.categories as string) ?? defaultCategories;\n\tconst categoriesArray = categories.split(',').map((cat) => cat.trim());\n\n\tconst ret = categoriesArray.map((cat) => ({ type: 'main', displayName: cat }));\n\treturn ret;\n};\n\nexport class SentimentAnalysis implements INodeType {\n\tdescription: INodeTypeDescription = {\n\t\tdisplayName: 'Sentiment Analysis',\n\t\tname: 'sentimentAnalysis',\n\t\ticon: 'fa:balance-scale-left',\n\t\ticonColor: 'black',\n\t\tgroup: ['transform'],\n\t\tversion: 1,\n\t\tdescription: 'Analyze the sentiment of your text',\n\t\tcodex: {\n\t\t\tcategories: ['AI'],\n\t\t\tsubcategories: {\n\t\t\t\tAI: ['Chains', 'Root Nodes'],\n\t\t\t},\n\t\t\tresources: {\n\t\t\t\tprimaryDocumentation: [\n\t\t\t\t\t{\n\t\t\t\t\t\turl: 'https://docs.n8n.io/integrations/builtin/cluster-nodes/root-nodes/n8n-nodes-langchain.sentimentanalysis/',\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t},\n\t\t},\n\t\tdefaults: {\n\t\t\tname: 'Sentiment Analysis',\n\t\t},\n\t\tinputs: [\n\t\t\t{ displayName: '', type: NodeConnectionTypes.Main },\n\t\t\t{\n\t\t\t\tdisplayName: 'Model',\n\t\t\t\tmaxConnections: 1,\n\t\t\t\ttype: NodeConnectionTypes.AiLanguageModel,\n\t\t\t\trequired: true,\n\t\t\t},\n\t\t],\n\t\toutputs: `={{(${configuredOutputs})($parameter, \"${DEFAULT_CATEGORIES}\")}}`,\n\t\tproperties: [\n\t\t\t{\n\t\t\t\tdisplayName: 'Text to Analyze',\n\t\t\t\tname: 'inputText',\n\t\t\t\ttype: 'string',\n\t\t\t\trequired: true,\n\t\t\t\tdefault: '',\n\t\t\t\tdescription: 'Use an expression to reference data in previous nodes or enter static text',\n\t\t\t\ttypeOptions: {\n\t\t\t\t\trows: 2,\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tdisplayName:\n\t\t\t\t\t'Sentiment scores are LLM-generated estimates, not statistically rigorous measurements. They may be inconsistent across runs and should be used as rough indicators only.',\n\t\t\t\tname: 'detailedResultsNotice',\n\t\t\t\ttype: 'notice',\n\t\t\t\tdefault: '',\n\t\t\t\tdisplayOptions: {\n\t\t\t\t\tshow: {\n\t\t\t\t\t\t'/options.includeDetailedResults': [true],\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tdisplayName: 'Options',\n\t\t\t\tname: 'options',\n\t\t\t\ttype: 'collection',\n\t\t\t\tdefault: {},\n\t\t\t\tplaceholder: 'Add Option',\n\t\t\t\toptions: [\n\t\t\t\t\t{\n\t\t\t\t\t\tdisplayName: 'Sentiment Categories',\n\t\t\t\t\t\tname: 'categories',\n\t\t\t\t\t\ttype: 'string',\n\t\t\t\t\t\tdefault: DEFAULT_CATEGORIES,\n\t\t\t\t\t\tdescription: 'A comma-separated list of categories to analyze',\n\t\t\t\t\t\tnoDataExpression: true,\n\t\t\t\t\t\ttypeOptions: {\n\t\t\t\t\t\t\trows: 2,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tdisplayName: 'System Prompt Template',\n\t\t\t\t\t\tname: 'systemPromptTemplate',\n\t\t\t\t\t\ttype: 'string',\n\t\t\t\t\t\tdefault: DEFAULT_SYSTEM_PROMPT_TEMPLATE,\n\t\t\t\t\t\tdescription: 'String to use directly as the system prompt template',\n\t\t\t\t\t\ttypeOptions: {\n\t\t\t\t\t\t\trows: 6,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tdisplayName: 'Include Detailed Results',\n\t\t\t\t\t\tname: 'includeDetailedResults',\n\t\t\t\t\t\ttype: 'boolean',\n\t\t\t\t\t\tdefault: false,\n\t\t\t\t\t\tdescription:\n\t\t\t\t\t\t\t'Whether to include sentiment strength and confidence scores in the output',\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tdisplayName: 'Enable Auto-Fixing',\n\t\t\t\t\t\tname: 'enableAutoFixing',\n\t\t\t\t\t\ttype: 'boolean',\n\t\t\t\t\t\tdefault: true,\n\t\t\t\t\t\tdescription:\n\t\t\t\t\t\t\t'Whether to enable auto-fixing (may trigger an additional LLM call if output is broken)',\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tdisplayName: 'Batch Processing',\n\t\t\t\t\t\tname: 'batching',\n\t\t\t\t\t\ttype: 'collection',\n\t\t\t\t\t\tdescription: 'Batch processing options for rate limiting',\n\t\t\t\t\t\tdefault: {},\n\t\t\t\t\t\toptions: [\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tdisplayName: 'Batch Size',\n\t\t\t\t\t\t\t\tname: 'batchSize',\n\t\t\t\t\t\t\t\tdefault: 100,\n\t\t\t\t\t\t\t\ttype: 'number',\n\t\t\t\t\t\t\t\tdescription:\n\t\t\t\t\t\t\t\t\t'How many items to process in parallel. This is useful for rate limiting.',\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tdisplayName: 'Delay Between Batches',\n\t\t\t\t\t\t\t\tname: 'delayBetweenBatches',\n\t\t\t\t\t\t\t\tdefault: 0,\n\t\t\t\t\t\t\t\ttype: 'number',\n\t\t\t\t\t\t\t\tdescription:\n\t\t\t\t\t\t\t\t\t'Delay in milliseconds between batches. This is useful for rate limiting.',\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t],\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t},\n\t\t],\n\t};\n\n\tasync execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]> {\n\t\tconst items = this.getInputData();\n\n\t\tconst llm = (await this.getInputConnectionData(\n\t\t\tNodeConnectionTypes.AiLanguageModel,\n\t\t\t0,\n\t\t)) as BaseLanguageModel;\n\n\t\tconst returnData: INodeExecutionData[][] = [];\n\t\tconst { batchSize, delayBetweenBatches } = this.getNodeParameter('options.batching', 0, {\n\t\t\tbatchSize: 100,\n\t\t\tdelayBetweenBatches: 0,\n\t\t}) as {\n\t\t\tbatchSize: number;\n\t\t\tdelayBetweenBatches: number;\n\t\t};\n\n\t\tfor (let i = 0; i < items.length; i += batchSize) {\n\t\t\tconst batch = items.slice(i, i + batchSize);\n\t\t\tconst batchPromises = batch.map(async (_item, batchItemIndex) => {\n\t\t\t\tconst itemIndex = i + batchItemIndex;\n\t\t\t\tconst sentimentCategories = this.getNodeParameter(\n\t\t\t\t\t'options.categories',\n\t\t\t\t\titemIndex,\n\t\t\t\t\tDEFAULT_CATEGORIES,\n\t\t\t\t) as string;\n\n\t\t\t\tconst categories = sentimentCategories\n\t\t\t\t\t.split(',')\n\t\t\t\t\t.map((cat) => cat.trim())\n\t\t\t\t\t.filter(Boolean);\n\n\t\t\t\tif (categories.length === 0) {\n\t\t\t\t\treturn {\n\t\t\t\t\t\tresult: null,\n\t\t\t\t\t\titemIndex,\n\t\t\t\t\t\terror: new NodeOperationError(this.getNode(), 'No sentiment categories provided', {\n\t\t\t\t\t\t\titemIndex,\n\t\t\t\t\t\t}),\n\t\t\t\t\t};\n\t\t\t\t}\n\n\t\t\t\t// Initialize returnData with empty arrays for each category\n\t\t\t\tif (returnData.length === 0) {\n\t\t\t\t\treturnData.push(...Array.from({ length: categories.length }, () => []));\n\t\t\t\t}\n\n\t\t\t\tconst options = this.getNodeParameter('options', itemIndex, {}) as {\n\t\t\t\t\tsystemPromptTemplate?: string;\n\t\t\t\t\tincludeDetailedResults?: boolean;\n\t\t\t\t\tenableAutoFixing?: boolean;\n\t\t\t\t};\n\n\t\t\t\tconst schema = z.object({\n\t\t\t\t\tsentiment: z.enum(categories as [string, ...string[]]),\n\t\t\t\t\tstrength: z\n\t\t\t\t\t\t.number()\n\t\t\t\t\t\t.min(0)\n\t\t\t\t\t\t.max(1)\n\t\t\t\t\t\t.describe('Strength score for sentiment in relation to the category'),\n\t\t\t\t\tconfidence: z.number().min(0).max(1),\n\t\t\t\t});\n\n\t\t\t\tconst structuredParser = StructuredOutputParser.fromZodSchema(schema);\n\n\t\t\t\tconst parser = options.enableAutoFixing\n\t\t\t\t\t? OutputFixingParser.fromLLM(llm, structuredParser)\n\t\t\t\t\t: structuredParser;\n\n\t\t\t\tconst systemPromptTemplate = SystemMessagePromptTemplate.fromTemplate(\n\t\t\t\t\t`${options.systemPromptTemplate ?? DEFAULT_SYSTEM_PROMPT_TEMPLATE}\n\t\t\t{format_instructions}`,\n\t\t\t\t);\n\n\t\t\t\tconst input = this.getNodeParameter('inputText', itemIndex) as string;\n\t\t\t\tconst inputPrompt = new HumanMessage(input);\n\t\t\t\tconst messages = [\n\t\t\t\t\tawait systemPromptTemplate.format({\n\t\t\t\t\t\tcategories: sentimentCategories,\n\t\t\t\t\t\tformat_instructions: parser.getFormatInstructions(),\n\t\t\t\t\t}),\n\t\t\t\t\tinputPrompt,\n\t\t\t\t];\n\n\t\t\t\tconst prompt = ChatPromptTemplate.fromMessages(messages);\n\t\t\t\tconst chain = prompt.pipe(llm).pipe(parser).withConfig(getTracingConfig(this));\n\n\t\t\t\ttry {\n\t\t\t\t\tconst output = await chain.invoke(messages);\n\t\t\t\t\tconst sentimentIndex = categories.findIndex(\n\t\t\t\t\t\t(s) => s.toLowerCase() === output.sentiment.toLowerCase(),\n\t\t\t\t\t);\n\n\t\t\t\t\tif (sentimentIndex !== -1) {\n\t\t\t\t\t\tconst resultItem = { ...items[itemIndex] };\n\t\t\t\t\t\tconst sentimentAnalysis: IDataObject = {\n\t\t\t\t\t\t\tcategory: output.sentiment,\n\t\t\t\t\t\t};\n\t\t\t\t\t\tif (options.includeDetailedResults) {\n\t\t\t\t\t\t\tsentimentAnalysis.strength = output.strength;\n\t\t\t\t\t\t\tsentimentAnalysis.confidence = output.confidence;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tresultItem.json = {\n\t\t\t\t\t\t\t...resultItem.json,\n\t\t\t\t\t\t\tsentimentAnalysis,\n\t\t\t\t\t\t};\n\n\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\tresult: {\n\t\t\t\t\t\t\t\tresultItem,\n\t\t\t\t\t\t\t\tsentimentIndex,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\titemIndex,\n\t\t\t\t\t\t};\n\t\t\t\t\t}\n\n\t\t\t\t\treturn {\n\t\t\t\t\t\tresult: {},\n\t\t\t\t\t\titemIndex,\n\t\t\t\t\t};\n\t\t\t\t} catch (error) {\n\t\t\t\t\treturn {\n\t\t\t\t\t\tresult: null,\n\t\t\t\t\t\titemIndex,\n\t\t\t\t\t\terror: new NodeOperationError(\n\t\t\t\t\t\t\tthis.getNode(),\n\t\t\t\t\t\t\t'Error during parsing of LLM output, please check your LLM model and configuration',\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\titemIndex,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t),\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t});\n\t\t\tconst batchResults = await Promise.all(batchPromises);\n\n\t\t\tbatchResults.forEach(({ result, itemIndex, error }) => {\n\t\t\t\tif (error) {\n\t\t\t\t\tif (this.continueOnFail()) {\n\t\t\t\t\t\tconst executionErrorData = this.helpers.constructExecutionMetaData(\n\t\t\t\t\t\t\tthis.helpers.returnJsonArray({ error: error.message }),\n\t\t\t\t\t\t\t{ itemData: { item: itemIndex } },\n\t\t\t\t\t\t);\n\n\t\t\t\t\t\treturnData[0].push(...executionErrorData);\n\t\t\t\t\t\treturn;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tthrow error;\n\t\t\t\t\t}\n\t\t\t\t} else if (result.resultItem && result.sentimentIndex) {\n\t\t\t\t\tconst sentimentIndex = result.sentimentIndex;\n\t\t\t\t\tconst resultItem = result.resultItem;\n\t\t\t\t\treturnData[sentimentIndex].push(resultItem);\n\t\t\t\t}\n\t\t\t});\n\n\t\t\t// Add delay between batches if not the last batch\n\t\t\tif (i + batchSize < items.length && delayBetweenBatches > 0) {\n\t\t\t\tawait sleep(delayBetweenBatches);\n\t\t\t}\n\t\t}\n\t\treturn returnData;\n\t}\n}\n"],"mappings":"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","names":[]}
@@ -166,6 +166,29 @@ class TextClassifier {
166
166
  type: "boolean",
167
167
  default: true,
168
168
  description: "Whether to enable auto-fixing (may trigger an additional LLM call if output is broken)"
169
+ },
170
+ {
171
+ displayName: "Batch Processing",
172
+ name: "batching",
173
+ type: "collection",
174
+ description: "Batch processing options for rate limiting",
175
+ default: {},
176
+ options: [
177
+ {
178
+ displayName: "Batch Size",
179
+ name: "batchSize",
180
+ default: 100,
181
+ type: "number",
182
+ description: "How many items to process in parallel. This is useful for rate limiting."
183
+ },
184
+ {
185
+ displayName: "Delay Between Batches",
186
+ name: "delayBetweenBatches",
187
+ default: 0,
188
+ type: "number",
189
+ description: "Delay in milliseconds between batches. This is useful for rate limiting."
190
+ }
191
+ ]
169
192
  }
170
193
  ]
171
194
  }
@@ -174,6 +197,10 @@ class TextClassifier {
174
197
  }
175
198
  async execute() {
176
199
  const items = this.getInputData();
200
+ const { batchSize, delayBetweenBatches } = this.getNodeParameter("options.batching", 0, {
201
+ batchSize: 100,
202
+ delayBetweenBatches: 0
203
+ });
177
204
  const llm = await this.getInputConnectionData(
178
205
  import_n8n_workflow.NodeConnectionTypes.AiLanguageModel,
179
206
  0
@@ -208,60 +235,67 @@ class TextClassifier {
208
235
  { length: categories.length + (fallback === "other" ? 1 : 0) },
209
236
  (_) => []
210
237
  );
211
- for (let itemIdx = 0; itemIdx < items.length; itemIdx++) {
212
- const item = items[itemIdx];
213
- item.pairedItem = { item: itemIdx };
214
- const input = this.getNodeParameter("inputText", itemIdx);
215
- if (input === void 0 || input === null) {
216
- if (this.continueOnFail()) {
217
- returnData[0].push({
218
- json: { error: "Text to classify is not defined" },
219
- pairedItem: { item: itemIdx }
220
- });
221
- continue;
222
- } else {
238
+ for (let i = 0; i < items.length; i += batchSize) {
239
+ const batch = items.slice(i, i + batchSize);
240
+ const batchPromises = batch.map(async (_item, batchItemIndex) => {
241
+ const itemIdx = i + batchItemIndex;
242
+ const item = items[itemIdx];
243
+ item.pairedItem = { item: itemIdx };
244
+ const input = this.getNodeParameter("inputText", itemIdx);
245
+ if (input === void 0 || input === null) {
223
246
  throw new import_n8n_workflow.NodeOperationError(
224
247
  this.getNode(),
225
248
  `Text to classify for item ${itemIdx} is not defined`
226
249
  );
227
250
  }
228
- }
229
- const inputPrompt = new import_messages.HumanMessage(input);
230
- const systemPromptTemplateOpt = this.getNodeParameter(
231
- "options.systemPromptTemplate",
232
- itemIdx,
233
- SYSTEM_PROMPT_TEMPLATE
234
- );
235
- const systemPromptTemplate = import_prompts.SystemMessagePromptTemplate.fromTemplate(
236
- `${systemPromptTemplateOpt ?? SYSTEM_PROMPT_TEMPLATE}
237
- {format_instructions}
238
- ${multiClassPrompt}
239
- ${fallbackPrompt}`
240
- );
241
- const messages = [
242
- await systemPromptTemplate.format({
243
- categories: categories.map((cat) => cat.category).join(", "),
244
- format_instructions: parser.getFormatInstructions()
245
- }),
246
- inputPrompt
247
- ];
248
- const prompt = import_prompts.ChatPromptTemplate.fromMessages(messages);
249
- const chain = prompt.pipe(llm).pipe(parser).withConfig((0, import_tracing.getTracingConfig)(this));
250
- try {
251
- const output = await chain.invoke(messages);
252
- categories.forEach((cat, idx) => {
253
- if (output[cat.category]) returnData[idx].push(item);
254
- });
255
- if (fallback === "other" && output.fallback) returnData[returnData.length - 1].push(item);
256
- } catch (error) {
257
- if (this.continueOnFail()) {
258
- returnData[0].push({
259
- json: { error: error.message },
260
- pairedItem: { item: itemIdx }
251
+ const inputPrompt = new import_messages.HumanMessage(input);
252
+ const systemPromptTemplateOpt = this.getNodeParameter(
253
+ "options.systemPromptTemplate",
254
+ itemIdx,
255
+ SYSTEM_PROMPT_TEMPLATE
256
+ );
257
+ const systemPromptTemplate = import_prompts.SystemMessagePromptTemplate.fromTemplate(
258
+ `${systemPromptTemplateOpt ?? SYSTEM_PROMPT_TEMPLATE}
259
+ {format_instructions}
260
+ ${multiClassPrompt}
261
+ ${fallbackPrompt}`
262
+ );
263
+ const messages = [
264
+ await systemPromptTemplate.format({
265
+ categories: categories.map((cat) => cat.category).join(", "),
266
+ format_instructions: parser.getFormatInstructions()
267
+ }),
268
+ inputPrompt
269
+ ];
270
+ const prompt = import_prompts.ChatPromptTemplate.fromMessages(messages);
271
+ const chain = prompt.pipe(llm).pipe(parser).withConfig((0, import_tracing.getTracingConfig)(this));
272
+ return await chain.invoke(messages);
273
+ });
274
+ const batchResults = await Promise.allSettled(batchPromises);
275
+ batchResults.forEach((response, batchItemIndex) => {
276
+ const index = i + batchItemIndex;
277
+ if (response.status === "rejected") {
278
+ const error = response.reason;
279
+ if (this.continueOnFail()) {
280
+ returnData[0].push({
281
+ json: { error: error.message },
282
+ pairedItem: { item: index }
283
+ });
284
+ return;
285
+ } else {
286
+ throw new import_n8n_workflow.NodeOperationError(this.getNode(), error.message);
287
+ }
288
+ } else {
289
+ const output = response.value;
290
+ const item = items[index];
291
+ categories.forEach((cat, idx) => {
292
+ if (output[cat.category]) returnData[idx].push(item);
261
293
  });
262
- continue;
294
+ if (fallback === "other" && output.fallback) returnData[returnData.length - 1].push(item);
263
295
  }
264
- throw error;
296
+ });
297
+ if (i + batchSize < items.length && delayBetweenBatches > 0) {
298
+ await (0, import_n8n_workflow.sleep)(delayBetweenBatches);
265
299
  }
266
300
  }
267
301
  return returnData;
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../nodes/chains/TextClassifier/TextClassifier.node.ts"],"sourcesContent":["import type { BaseLanguageModel } from '@langchain/core/language_models/base';\nimport { HumanMessage } from '@langchain/core/messages';\nimport { SystemMessagePromptTemplate, ChatPromptTemplate } from '@langchain/core/prompts';\nimport { OutputFixingParser, StructuredOutputParser } from 'langchain/output_parsers';\nimport { NodeOperationError, NodeConnectionTypes } from 'n8n-workflow';\nimport type {\n\tIDataObject,\n\tIExecuteFunctions,\n\tINodeExecutionData,\n\tINodeParameters,\n\tINodeType,\n\tINodeTypeDescription,\n} from 'n8n-workflow';\nimport { z } from 'zod';\n\nimport { getTracingConfig } from '@utils/tracing';\n\nconst SYSTEM_PROMPT_TEMPLATE =\n\t\"Please classify the text provided by the user into one of the following categories: {categories}, and use the provided formatting instructions below. Don't explain, and only output the json.\";\n\nconst configuredOutputs = (parameters: INodeParameters) => {\n\tconst categories = ((parameters.categories as IDataObject)?.categories as IDataObject[]) ?? [];\n\tconst fallback = (parameters.options as IDataObject)?.fallback as string;\n\tconst ret = categories.map((cat) => {\n\t\treturn { type: 'main', displayName: cat.category };\n\t});\n\tif (fallback === 'other') ret.push({ type: 'main', displayName: 'Other' });\n\treturn ret;\n};\n\nexport class TextClassifier implements INodeType {\n\tdescription: INodeTypeDescription = {\n\t\tdisplayName: 'Text Classifier',\n\t\tname: 'textClassifier',\n\t\ticon: 'fa:tags',\n\t\ticonColor: 'black',\n\t\tgroup: ['transform'],\n\t\tversion: 1,\n\t\tdescription: 'Classify your text into distinct categories',\n\t\tcodex: {\n\t\t\tcategories: ['AI'],\n\t\t\tsubcategories: {\n\t\t\t\tAI: ['Chains', 'Root Nodes'],\n\t\t\t},\n\t\t\tresources: {\n\t\t\t\tprimaryDocumentation: [\n\t\t\t\t\t{\n\t\t\t\t\t\turl: 'https://docs.n8n.io/integrations/builtin/cluster-nodes/root-nodes/n8n-nodes-langchain.text-classifier/',\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t},\n\t\t},\n\t\tdefaults: {\n\t\t\tname: 'Text Classifier',\n\t\t},\n\t\tinputs: [\n\t\t\t{ displayName: '', type: NodeConnectionTypes.Main },\n\t\t\t{\n\t\t\t\tdisplayName: 'Model',\n\t\t\t\tmaxConnections: 1,\n\t\t\t\ttype: NodeConnectionTypes.AiLanguageModel,\n\t\t\t\trequired: true,\n\t\t\t},\n\t\t],\n\t\toutputs: `={{(${configuredOutputs})($parameter)}}`,\n\t\tproperties: [\n\t\t\t{\n\t\t\t\tdisplayName: 'Text to Classify',\n\t\t\t\tname: 'inputText',\n\t\t\t\ttype: 'string',\n\t\t\t\trequired: true,\n\t\t\t\tdefault: '',\n\t\t\t\tdescription: 'Use an expression to reference data in previous nodes or enter static text',\n\t\t\t\ttypeOptions: {\n\t\t\t\t\trows: 2,\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tdisplayName: 'Categories',\n\t\t\t\tname: 'categories',\n\t\t\t\tplaceholder: 'Add Category',\n\t\t\t\ttype: 'fixedCollection',\n\t\t\t\tdefault: {},\n\t\t\t\ttypeOptions: {\n\t\t\t\t\tmultipleValues: true,\n\t\t\t\t},\n\t\t\t\toptions: [\n\t\t\t\t\t{\n\t\t\t\t\t\tname: 'categories',\n\t\t\t\t\t\tdisplayName: 'Categories',\n\t\t\t\t\t\tvalues: [\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tdisplayName: 'Category',\n\t\t\t\t\t\t\t\tname: 'category',\n\t\t\t\t\t\t\t\ttype: 'string',\n\t\t\t\t\t\t\t\tdefault: '',\n\t\t\t\t\t\t\t\tdescription: 'Category to add',\n\t\t\t\t\t\t\t\trequired: true,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tdisplayName: 'Description',\n\t\t\t\t\t\t\t\tname: 'description',\n\t\t\t\t\t\t\t\ttype: 'string',\n\t\t\t\t\t\t\t\tdefault: '',\n\t\t\t\t\t\t\t\tdescription: \"Describe your category if it's not obvious\",\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t],\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t},\n\t\t\t{\n\t\t\t\tdisplayName: 'Options',\n\t\t\t\tname: 'options',\n\t\t\t\ttype: 'collection',\n\t\t\t\tdefault: {},\n\t\t\t\tplaceholder: 'Add Option',\n\t\t\t\toptions: [\n\t\t\t\t\t{\n\t\t\t\t\t\tdisplayName: 'Allow Multiple Classes To Be True',\n\t\t\t\t\t\tname: 'multiClass',\n\t\t\t\t\t\ttype: 'boolean',\n\t\t\t\t\t\tdefault: false,\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tdisplayName: 'When No Clear Match',\n\t\t\t\t\t\tname: 'fallback',\n\t\t\t\t\t\ttype: 'options',\n\t\t\t\t\t\tdefault: 'discard',\n\t\t\t\t\t\tdescription: 'What to do with items that don’t match the categories exactly',\n\t\t\t\t\t\toptions: [\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tname: 'Discard Item',\n\t\t\t\t\t\t\t\tvalue: 'discard',\n\t\t\t\t\t\t\t\tdescription: 'Ignore the item and drop it from the output',\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tname: \"Output on Extra, 'Other' Branch\",\n\t\t\t\t\t\t\t\tvalue: 'other',\n\t\t\t\t\t\t\t\tdescription: \"Create a separate output branch called 'Other'\",\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t],\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tdisplayName: 'System Prompt Template',\n\t\t\t\t\t\tname: 'systemPromptTemplate',\n\t\t\t\t\t\ttype: 'string',\n\t\t\t\t\t\tdefault: SYSTEM_PROMPT_TEMPLATE,\n\t\t\t\t\t\tdescription: 'String to use directly as the system prompt template',\n\t\t\t\t\t\ttypeOptions: {\n\t\t\t\t\t\t\trows: 6,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tdisplayName: 'Enable Auto-Fixing',\n\t\t\t\t\t\tname: 'enableAutoFixing',\n\t\t\t\t\t\ttype: 'boolean',\n\t\t\t\t\t\tdefault: true,\n\t\t\t\t\t\tdescription:\n\t\t\t\t\t\t\t'Whether to enable auto-fixing (may trigger an additional LLM call if output is broken)',\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t},\n\t\t],\n\t};\n\n\tasync execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]> {\n\t\tconst items = this.getInputData();\n\n\t\tconst llm = (await this.getInputConnectionData(\n\t\t\tNodeConnectionTypes.AiLanguageModel,\n\t\t\t0,\n\t\t)) as BaseLanguageModel;\n\n\t\tconst categories = this.getNodeParameter('categories.categories', 0, []) as Array<{\n\t\t\tcategory: string;\n\t\t\tdescription: string;\n\t\t}>;\n\n\t\tif (categories.length === 0) {\n\t\t\tthrow new NodeOperationError(this.getNode(), 'At least one category must be defined');\n\t\t}\n\n\t\tconst options = this.getNodeParameter('options', 0, {}) as {\n\t\t\tmultiClass: boolean;\n\t\t\tfallback?: string;\n\t\t\tsystemPromptTemplate?: string;\n\t\t\tenableAutoFixing: boolean;\n\t\t};\n\t\tconst multiClass = options?.multiClass ?? false;\n\t\tconst fallback = options?.fallback ?? 'discard';\n\n\t\tconst schemaEntries = categories.map((cat) => [\n\t\t\tcat.category,\n\t\t\tz\n\t\t\t\t.boolean()\n\t\t\t\t.describe(\n\t\t\t\t\t`Should be true if the input has category \"${cat.category}\" (description: ${cat.description})`,\n\t\t\t\t),\n\t\t]);\n\t\tif (fallback === 'other')\n\t\t\tschemaEntries.push([\n\t\t\t\t'fallback',\n\t\t\t\tz.boolean().describe('Should be true if none of the other categories apply'),\n\t\t\t]);\n\t\tconst schema = z.object(Object.fromEntries(schemaEntries));\n\n\t\tconst structuredParser = StructuredOutputParser.fromZodSchema(schema);\n\n\t\tconst parser = options.enableAutoFixing\n\t\t\t? OutputFixingParser.fromLLM(llm, structuredParser)\n\t\t\t: structuredParser;\n\n\t\tconst multiClassPrompt = multiClass\n\t\t\t? 'Categories are not mutually exclusive, and multiple can be true'\n\t\t\t: 'Categories are mutually exclusive, and only one can be true';\n\n\t\tconst fallbackPrompt = {\n\t\t\tother: 'If no categories apply, select the \"fallback\" option.',\n\t\t\tdiscard: 'If there is not a very fitting category, select none of the categories.',\n\t\t}[fallback];\n\n\t\tconst returnData: INodeExecutionData[][] = Array.from(\n\t\t\t{ length: categories.length + (fallback === 'other' ? 1 : 0) },\n\t\t\t(_) => [],\n\t\t);\n\t\tfor (let itemIdx = 0; itemIdx < items.length; itemIdx++) {\n\t\t\tconst item = items[itemIdx];\n\t\t\titem.pairedItem = { item: itemIdx };\n\t\t\tconst input = this.getNodeParameter('inputText', itemIdx) as string;\n\n\t\t\tif (input === undefined || input === null) {\n\t\t\t\tif (this.continueOnFail()) {\n\t\t\t\t\treturnData[0].push({\n\t\t\t\t\t\tjson: { error: 'Text to classify is not defined' },\n\t\t\t\t\t\tpairedItem: { item: itemIdx },\n\t\t\t\t\t});\n\t\t\t\t\tcontinue;\n\t\t\t\t} else {\n\t\t\t\t\tthrow new NodeOperationError(\n\t\t\t\t\t\tthis.getNode(),\n\t\t\t\t\t\t`Text to classify for item ${itemIdx} is not defined`,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst inputPrompt = new HumanMessage(input);\n\n\t\t\tconst systemPromptTemplateOpt = this.getNodeParameter(\n\t\t\t\t'options.systemPromptTemplate',\n\t\t\t\titemIdx,\n\t\t\t\tSYSTEM_PROMPT_TEMPLATE,\n\t\t\t) as string;\n\t\t\tconst systemPromptTemplate = SystemMessagePromptTemplate.fromTemplate(\n\t\t\t\t`${systemPromptTemplateOpt ?? SYSTEM_PROMPT_TEMPLATE}\n{format_instructions}\n${multiClassPrompt}\n${fallbackPrompt}`,\n\t\t\t);\n\n\t\t\tconst messages = [\n\t\t\t\tawait systemPromptTemplate.format({\n\t\t\t\t\tcategories: categories.map((cat) => cat.category).join(', '),\n\t\t\t\t\tformat_instructions: parser.getFormatInstructions(),\n\t\t\t\t}),\n\t\t\t\tinputPrompt,\n\t\t\t];\n\t\t\tconst prompt = ChatPromptTemplate.fromMessages(messages);\n\t\t\tconst chain = prompt.pipe(llm).pipe(parser).withConfig(getTracingConfig(this));\n\n\t\t\ttry {\n\t\t\t\tconst output = await chain.invoke(messages);\n\n\t\t\t\tcategories.forEach((cat, idx) => {\n\t\t\t\t\tif (output[cat.category]) returnData[idx].push(item);\n\t\t\t\t});\n\t\t\t\tif (fallback === 'other' && output.fallback) returnData[returnData.length - 1].push(item);\n\t\t\t} catch (error) {\n\t\t\t\tif (this.continueOnFail()) {\n\t\t\t\t\treturnData[0].push({\n\t\t\t\t\t\tjson: { error: error.message },\n\t\t\t\t\t\tpairedItem: { item: itemIdx },\n\t\t\t\t\t});\n\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t}\n\n\t\treturn returnData;\n\t}\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../../../nodes/chains/TextClassifier/TextClassifier.node.ts"],"sourcesContent":["import type { BaseLanguageModel } from '@langchain/core/language_models/base';\nimport { HumanMessage } from '@langchain/core/messages';\nimport { SystemMessagePromptTemplate, ChatPromptTemplate } from '@langchain/core/prompts';\nimport { OutputFixingParser, StructuredOutputParser } from 'langchain/output_parsers';\nimport { NodeOperationError, NodeConnectionTypes, sleep } from 'n8n-workflow';\nimport type {\n\tIDataObject,\n\tIExecuteFunctions,\n\tINodeExecutionData,\n\tINodeParameters,\n\tINodeType,\n\tINodeTypeDescription,\n} from 'n8n-workflow';\nimport { z } from 'zod';\n\nimport { getTracingConfig } from '@utils/tracing';\n\nconst SYSTEM_PROMPT_TEMPLATE =\n\t\"Please classify the text provided by the user into one of the following categories: {categories}, and use the provided formatting instructions below. Don't explain, and only output the json.\";\n\nconst configuredOutputs = (parameters: INodeParameters) => {\n\tconst categories = ((parameters.categories as IDataObject)?.categories as IDataObject[]) ?? [];\n\tconst fallback = (parameters.options as IDataObject)?.fallback as string;\n\tconst ret = categories.map((cat) => {\n\t\treturn { type: 'main', displayName: cat.category };\n\t});\n\tif (fallback === 'other') ret.push({ type: 'main', displayName: 'Other' });\n\treturn ret;\n};\n\nexport class TextClassifier implements INodeType {\n\tdescription: INodeTypeDescription = {\n\t\tdisplayName: 'Text Classifier',\n\t\tname: 'textClassifier',\n\t\ticon: 'fa:tags',\n\t\ticonColor: 'black',\n\t\tgroup: ['transform'],\n\t\tversion: 1,\n\t\tdescription: 'Classify your text into distinct categories',\n\t\tcodex: {\n\t\t\tcategories: ['AI'],\n\t\t\tsubcategories: {\n\t\t\t\tAI: ['Chains', 'Root Nodes'],\n\t\t\t},\n\t\t\tresources: {\n\t\t\t\tprimaryDocumentation: [\n\t\t\t\t\t{\n\t\t\t\t\t\turl: 'https://docs.n8n.io/integrations/builtin/cluster-nodes/root-nodes/n8n-nodes-langchain.text-classifier/',\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t},\n\t\t},\n\t\tdefaults: {\n\t\t\tname: 'Text Classifier',\n\t\t},\n\t\tinputs: [\n\t\t\t{ displayName: '', type: NodeConnectionTypes.Main },\n\t\t\t{\n\t\t\t\tdisplayName: 'Model',\n\t\t\t\tmaxConnections: 1,\n\t\t\t\ttype: NodeConnectionTypes.AiLanguageModel,\n\t\t\t\trequired: true,\n\t\t\t},\n\t\t],\n\t\toutputs: `={{(${configuredOutputs})($parameter)}}`,\n\t\tproperties: [\n\t\t\t{\n\t\t\t\tdisplayName: 'Text to Classify',\n\t\t\t\tname: 'inputText',\n\t\t\t\ttype: 'string',\n\t\t\t\trequired: true,\n\t\t\t\tdefault: '',\n\t\t\t\tdescription: 'Use an expression to reference data in previous nodes or enter static text',\n\t\t\t\ttypeOptions: {\n\t\t\t\t\trows: 2,\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tdisplayName: 'Categories',\n\t\t\t\tname: 'categories',\n\t\t\t\tplaceholder: 'Add Category',\n\t\t\t\ttype: 'fixedCollection',\n\t\t\t\tdefault: {},\n\t\t\t\ttypeOptions: {\n\t\t\t\t\tmultipleValues: true,\n\t\t\t\t},\n\t\t\t\toptions: [\n\t\t\t\t\t{\n\t\t\t\t\t\tname: 'categories',\n\t\t\t\t\t\tdisplayName: 'Categories',\n\t\t\t\t\t\tvalues: [\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tdisplayName: 'Category',\n\t\t\t\t\t\t\t\tname: 'category',\n\t\t\t\t\t\t\t\ttype: 'string',\n\t\t\t\t\t\t\t\tdefault: '',\n\t\t\t\t\t\t\t\tdescription: 'Category to add',\n\t\t\t\t\t\t\t\trequired: true,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tdisplayName: 'Description',\n\t\t\t\t\t\t\t\tname: 'description',\n\t\t\t\t\t\t\t\ttype: 'string',\n\t\t\t\t\t\t\t\tdefault: '',\n\t\t\t\t\t\t\t\tdescription: \"Describe your category if it's not obvious\",\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t],\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t},\n\t\t\t{\n\t\t\t\tdisplayName: 'Options',\n\t\t\t\tname: 'options',\n\t\t\t\ttype: 'collection',\n\t\t\t\tdefault: {},\n\t\t\t\tplaceholder: 'Add Option',\n\t\t\t\toptions: [\n\t\t\t\t\t{\n\t\t\t\t\t\tdisplayName: 'Allow Multiple Classes To Be True',\n\t\t\t\t\t\tname: 'multiClass',\n\t\t\t\t\t\ttype: 'boolean',\n\t\t\t\t\t\tdefault: false,\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tdisplayName: 'When No Clear Match',\n\t\t\t\t\t\tname: 'fallback',\n\t\t\t\t\t\ttype: 'options',\n\t\t\t\t\t\tdefault: 'discard',\n\t\t\t\t\t\tdescription: 'What to do with items that don’t match the categories exactly',\n\t\t\t\t\t\toptions: [\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tname: 'Discard Item',\n\t\t\t\t\t\t\t\tvalue: 'discard',\n\t\t\t\t\t\t\t\tdescription: 'Ignore the item and drop it from the output',\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tname: \"Output on Extra, 'Other' Branch\",\n\t\t\t\t\t\t\t\tvalue: 'other',\n\t\t\t\t\t\t\t\tdescription: \"Create a separate output branch called 'Other'\",\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t],\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tdisplayName: 'System Prompt Template',\n\t\t\t\t\t\tname: 'systemPromptTemplate',\n\t\t\t\t\t\ttype: 'string',\n\t\t\t\t\t\tdefault: SYSTEM_PROMPT_TEMPLATE,\n\t\t\t\t\t\tdescription: 'String to use directly as the system prompt template',\n\t\t\t\t\t\ttypeOptions: {\n\t\t\t\t\t\t\trows: 6,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tdisplayName: 'Enable Auto-Fixing',\n\t\t\t\t\t\tname: 'enableAutoFixing',\n\t\t\t\t\t\ttype: 'boolean',\n\t\t\t\t\t\tdefault: true,\n\t\t\t\t\t\tdescription:\n\t\t\t\t\t\t\t'Whether to enable auto-fixing (may trigger an additional LLM call if output is broken)',\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tdisplayName: 'Batch Processing',\n\t\t\t\t\t\tname: 'batching',\n\t\t\t\t\t\ttype: 'collection',\n\t\t\t\t\t\tdescription: 'Batch processing options for rate limiting',\n\t\t\t\t\t\tdefault: {},\n\t\t\t\t\t\toptions: [\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tdisplayName: 'Batch Size',\n\t\t\t\t\t\t\t\tname: 'batchSize',\n\t\t\t\t\t\t\t\tdefault: 100,\n\t\t\t\t\t\t\t\ttype: 'number',\n\t\t\t\t\t\t\t\tdescription:\n\t\t\t\t\t\t\t\t\t'How many items to process in parallel. This is useful for rate limiting.',\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tdisplayName: 'Delay Between Batches',\n\t\t\t\t\t\t\t\tname: 'delayBetweenBatches',\n\t\t\t\t\t\t\t\tdefault: 0,\n\t\t\t\t\t\t\t\ttype: 'number',\n\t\t\t\t\t\t\t\tdescription:\n\t\t\t\t\t\t\t\t\t'Delay in milliseconds between batches. This is useful for rate limiting.',\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t],\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t},\n\t\t],\n\t};\n\n\tasync execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]> {\n\t\tconst items = this.getInputData();\n\t\tconst { batchSize, delayBetweenBatches } = this.getNodeParameter('options.batching', 0, {\n\t\t\tbatchSize: 100,\n\t\t\tdelayBetweenBatches: 0,\n\t\t}) as {\n\t\t\tbatchSize: number;\n\t\t\tdelayBetweenBatches: number;\n\t\t};\n\n\t\tconst llm = (await this.getInputConnectionData(\n\t\t\tNodeConnectionTypes.AiLanguageModel,\n\t\t\t0,\n\t\t)) as BaseLanguageModel;\n\n\t\tconst categories = this.getNodeParameter('categories.categories', 0, []) as Array<{\n\t\t\tcategory: string;\n\t\t\tdescription: string;\n\t\t}>;\n\n\t\tif (categories.length === 0) {\n\t\t\tthrow new NodeOperationError(this.getNode(), 'At least one category must be defined');\n\t\t}\n\n\t\tconst options = this.getNodeParameter('options', 0, {}) as {\n\t\t\tmultiClass: boolean;\n\t\t\tfallback?: string;\n\t\t\tsystemPromptTemplate?: string;\n\t\t\tenableAutoFixing: boolean;\n\t\t};\n\t\tconst multiClass = options?.multiClass ?? false;\n\t\tconst fallback = options?.fallback ?? 'discard';\n\n\t\tconst schemaEntries = categories.map((cat) => [\n\t\t\tcat.category,\n\t\t\tz\n\t\t\t\t.boolean()\n\t\t\t\t.describe(\n\t\t\t\t\t`Should be true if the input has category \"${cat.category}\" (description: ${cat.description})`,\n\t\t\t\t),\n\t\t]);\n\t\tif (fallback === 'other')\n\t\t\tschemaEntries.push([\n\t\t\t\t'fallback',\n\t\t\t\tz.boolean().describe('Should be true if none of the other categories apply'),\n\t\t\t]);\n\t\tconst schema = z.object(Object.fromEntries(schemaEntries));\n\n\t\tconst structuredParser = StructuredOutputParser.fromZodSchema(schema);\n\n\t\tconst parser = options.enableAutoFixing\n\t\t\t? OutputFixingParser.fromLLM(llm, structuredParser)\n\t\t\t: structuredParser;\n\n\t\tconst multiClassPrompt = multiClass\n\t\t\t? 'Categories are not mutually exclusive, and multiple can be true'\n\t\t\t: 'Categories are mutually exclusive, and only one can be true';\n\n\t\tconst fallbackPrompt = {\n\t\t\tother: 'If no categories apply, select the \"fallback\" option.',\n\t\t\tdiscard: 'If there is not a very fitting category, select none of the categories.',\n\t\t}[fallback];\n\n\t\tconst returnData: INodeExecutionData[][] = Array.from(\n\t\t\t{ length: categories.length + (fallback === 'other' ? 1 : 0) },\n\t\t\t(_) => [],\n\t\t);\n\n\t\tfor (let i = 0; i < items.length; i += batchSize) {\n\t\t\tconst batch = items.slice(i, i + batchSize);\n\t\t\tconst batchPromises = batch.map(async (_item, batchItemIndex) => {\n\t\t\t\tconst itemIdx = i + batchItemIndex;\n\t\t\t\tconst item = items[itemIdx];\n\t\t\t\titem.pairedItem = { item: itemIdx };\n\t\t\t\tconst input = this.getNodeParameter('inputText', itemIdx) as string;\n\n\t\t\t\tif (input === undefined || input === null) {\n\t\t\t\t\tthrow new NodeOperationError(\n\t\t\t\t\t\tthis.getNode(),\n\t\t\t\t\t\t`Text to classify for item ${itemIdx} is not defined`,\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\tconst inputPrompt = new HumanMessage(input);\n\n\t\t\t\tconst systemPromptTemplateOpt = this.getNodeParameter(\n\t\t\t\t\t'options.systemPromptTemplate',\n\t\t\t\t\titemIdx,\n\t\t\t\t\tSYSTEM_PROMPT_TEMPLATE,\n\t\t\t\t) as string;\n\t\t\t\tconst systemPromptTemplate = SystemMessagePromptTemplate.fromTemplate(\n\t\t\t\t\t`${systemPromptTemplateOpt ?? SYSTEM_PROMPT_TEMPLATE}\n\t{format_instructions}\n\t${multiClassPrompt}\n\t${fallbackPrompt}`,\n\t\t\t\t);\n\n\t\t\t\tconst messages = [\n\t\t\t\t\tawait systemPromptTemplate.format({\n\t\t\t\t\t\tcategories: categories.map((cat) => cat.category).join(', '),\n\t\t\t\t\t\tformat_instructions: parser.getFormatInstructions(),\n\t\t\t\t\t}),\n\t\t\t\t\tinputPrompt,\n\t\t\t\t];\n\t\t\t\tconst prompt = ChatPromptTemplate.fromMessages(messages);\n\t\t\t\tconst chain = prompt.pipe(llm).pipe(parser).withConfig(getTracingConfig(this));\n\n\t\t\t\treturn await chain.invoke(messages);\n\t\t\t});\n\n\t\t\tconst batchResults = await Promise.allSettled(batchPromises);\n\n\t\t\tbatchResults.forEach((response, batchItemIndex) => {\n\t\t\t\tconst index = i + batchItemIndex;\n\t\t\t\tif (response.status === 'rejected') {\n\t\t\t\t\tconst error = response.reason as Error;\n\t\t\t\t\tif (this.continueOnFail()) {\n\t\t\t\t\t\treturnData[0].push({\n\t\t\t\t\t\t\tjson: { error: error.message },\n\t\t\t\t\t\t\tpairedItem: { item: index },\n\t\t\t\t\t\t});\n\t\t\t\t\t\treturn;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tthrow new NodeOperationError(this.getNode(), error.message);\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tconst output = response.value;\n\t\t\t\t\tconst item = items[index];\n\n\t\t\t\t\tcategories.forEach((cat, idx) => {\n\t\t\t\t\t\tif (output[cat.category]) returnData[idx].push(item);\n\t\t\t\t\t});\n\n\t\t\t\t\tif (fallback === 'other' && output.fallback) returnData[returnData.length - 1].push(item);\n\t\t\t\t}\n\t\t\t});\n\n\t\t\t// Add delay between batches if not the last batch\n\t\t\tif (i + batchSize < items.length && delayBetweenBatches > 0) {\n\t\t\t\tawait sleep(delayBetweenBatches);\n\t\t\t}\n\t\t}\n\n\t\treturn returnData;\n\t}\n}\n"],"mappings":"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","names":[]}
@@ -269,7 +269,10 @@ class LmChatAnthropic {
269
269
  };
270
270
  }
271
271
  async supplyData(itemIndex) {
272
- const credentials = await this.getCredentials("anthropicApi");
272
+ const credentials = await this.getCredentials(
273
+ "anthropicApi"
274
+ );
275
+ const baseURL = credentials.url ?? "https://api.anthropic.com";
273
276
  const version = this.getNode().typeVersion;
274
277
  const modelName = version >= 1.3 ? this.getNodeParameter("model.value", itemIndex) : this.getNodeParameter("model", itemIndex);
275
278
  const options = this.getNodeParameter("options", itemIndex, {});
@@ -307,6 +310,7 @@ class LmChatAnthropic {
307
310
  const model = new import_anthropic.ChatAnthropic({
308
311
  anthropicApiKey: credentials.apiKey,
309
312
  modelName,
313
+ anthropicApiUrl: baseURL,
310
314
  maxTokens: options.maxTokensToSample,
311
315
  temperature: options.temperature,
312
316
  topK: options.topK,