@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.
- package/dist/credentials/AnthropicApi.credentials.js +8 -1
- package/dist/credentials/AnthropicApi.credentials.js.map +1 -1
- package/dist/credentials/AzureEntraCognitiveServicesOAuth2Api.credentials.js +150 -0
- package/dist/credentials/AzureEntraCognitiveServicesOAuth2Api.credentials.js.map +1 -0
- package/dist/known/credentials.json +10 -0
- package/dist/nodes/agents/Agent/agents/ToolsAgent/description.js +23 -0
- package/dist/nodes/agents/Agent/agents/ToolsAgent/description.js.map +1 -1
- package/dist/nodes/agents/Agent/agents/ToolsAgent/execute.js +28 -13
- package/dist/nodes/agents/Agent/agents/ToolsAgent/execute.js.map +1 -1
- package/dist/nodes/chains/ChainLLM/ChainLlm.node.js +39 -21
- package/dist/nodes/chains/ChainLLM/ChainLlm.node.js.map +1 -1
- package/dist/nodes/chains/ChainLLM/methods/config.js +24 -0
- package/dist/nodes/chains/ChainLLM/methods/config.js.map +1 -1
- package/dist/nodes/chains/ChainRetrievalQA/ChainRetrievalQa.node.js +55 -15
- package/dist/nodes/chains/ChainRetrievalQA/ChainRetrievalQa.node.js.map +1 -1
- package/dist/nodes/chains/ChainSummarization/V2/ChainSummarizationV2.node.js +54 -11
- package/dist/nodes/chains/ChainSummarization/V2/ChainSummarizationV2.node.js.map +1 -1
- package/dist/nodes/chains/InformationExtractor/InformationExtractor.node.js +66 -24
- package/dist/nodes/chains/InformationExtractor/InformationExtractor.node.js.map +1 -1
- package/dist/nodes/chains/SentimentAnalysis/SentimentAnalysis.node.js +86 -27
- package/dist/nodes/chains/SentimentAnalysis/SentimentAnalysis.node.js.map +1 -1
- package/dist/nodes/chains/TextClassifier/TextClassifier.node.js +81 -47
- package/dist/nodes/chains/TextClassifier/TextClassifier.node.js.map +1 -1
- package/dist/nodes/llms/LMChatAnthropic/LmChatAnthropic.node.js +5 -1
- package/dist/nodes/llms/LMChatAnthropic/LmChatAnthropic.node.js.map +1 -1
- package/dist/nodes/llms/LMChatAnthropic/methods/searchModels.js +3 -1
- package/dist/nodes/llms/LMChatAnthropic/methods/searchModels.js.map +1 -1
- package/dist/nodes/llms/LmChatAzureOpenAi/LmChatAzureOpenAi.node.js +63 -123
- package/dist/nodes/llms/LmChatAzureOpenAi/LmChatAzureOpenAi.node.js.map +1 -1
- package/dist/nodes/llms/LmChatAzureOpenAi/credentials/N8nOAuth2TokenCredential.js +61 -0
- package/dist/nodes/llms/LmChatAzureOpenAi/credentials/N8nOAuth2TokenCredential.js.map +1 -0
- package/dist/nodes/llms/LmChatAzureOpenAi/credentials/api-key.js +53 -0
- package/dist/nodes/llms/LmChatAzureOpenAi/credentials/api-key.js.map +1 -0
- package/dist/nodes/llms/LmChatAzureOpenAi/credentials/oauth2.js +54 -0
- package/dist/nodes/llms/LmChatAzureOpenAi/credentials/oauth2.js.map +1 -0
- package/dist/nodes/llms/LmChatAzureOpenAi/properties.js +155 -0
- package/dist/nodes/llms/LmChatAzureOpenAi/properties.js.map +1 -0
- package/dist/nodes/llms/LmChatAzureOpenAi/types.js +42 -0
- package/dist/nodes/llms/LmChatAzureOpenAi/types.js.map +1 -0
- package/dist/types/credentials.json +2 -1
- package/dist/types/nodes.json +8 -8
- 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
|
-
|
|
153
|
-
|
|
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
|
-
|
|
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
|
-
|
|
162
|
-
|
|
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",
|
|
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
|
-
|
|
211
|
+
{format_instructions}`
|
|
179
212
|
);
|
|
180
|
-
const input = this.getNodeParameter("inputText",
|
|
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[
|
|
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
|
-
|
|
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
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
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
|
-
}
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
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
|
-
|
|
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
|
|
212
|
-
const
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
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
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
{
|
|
238
|
-
${
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
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
|
-
|
|
294
|
+
if (fallback === "other" && output.fallback) returnData[returnData.length - 1].push(item);
|
|
263
295
|
}
|
|
264
|
-
|
|
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(
|
|
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,
|