"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.InformationExtractor = void 0;
const output_parsers_1 = require("@langchain/classic/output_parsers");
const n8n_workflow_1 = require("n8n-workflow");
const descriptions_1 = require("../../../utils/descriptions");
const schemaParsing_1 = require("../../../utils/schemaParsing");
const ai_utilities_1 = require("@n8n/ai-utilities");
const constants_1 = require("./constants");
const helpers_1 = require("./helpers");
const processItem_1 = require("./processItem");
class InformationExtractor {
    constructor() {
        this.description = {
            displayName: 'Information Extractor',
            name: 'informationExtractor',
            icon: 'node:information-extractor',
            iconColor: 'black',
            group: ['transform'],
            version: [1, 1.1, 1.2],
            defaultVersion: 1.2,
            description: 'Extract information from text in a structured format',
            codex: {
                alias: ['NER', 'parse', 'parsing', 'JSON', 'data extraction', 'structured'],
                categories: ['AI'],
                subcategories: {
                    AI: ['Chains', 'Root Nodes'],
                },
                resources: {
                    primaryDocumentation: [
                        {
                            url: 'https://docs.n8n.io/integrations/builtin/cluster-nodes/root-nodes/n8n-nodes-langchain.information-extractor/',
                        },
                    ],
                },
            },
            defaults: {
                name: 'Information Extractor',
            },
            inputs: [
                { displayName: '', type: n8n_workflow_1.NodeConnectionTypes.Main },
                {
                    displayName: 'Model',
                    maxConnections: 1,
                    type: n8n_workflow_1.NodeConnectionTypes.AiLanguageModel,
                    required: true,
                },
            ],
            outputs: [n8n_workflow_1.NodeConnectionTypes.Main],
            builderHint: {
                inputs: {
                    ai_languageModel: { required: true },
                },
            },
            properties: [
                {
                    displayName: 'Text',
                    name: 'text',
                    type: 'string',
                    default: '',
                    description: 'The text to extract information from',
                    typeOptions: {
                        rows: 2,
                    },
                },
                {
                    ...descriptions_1.schemaTypeField,
                    description: 'How to specify the schema for the desired output',
                    options: [
                        {
                            name: 'From Attribute Descriptions',
                            value: 'fromAttributes',
                            description: 'Extract specific attributes from the text based on types and descriptions',
                        },
                        ...descriptions_1.schemaTypeField.options,
                    ],
                    default: 'fromAttributes',
                },
                {
                    ...descriptions_1.jsonSchemaExampleField,
                    default: `{
	"state": "California",
	"cities": ["Los Angeles", "San Francisco", "San Diego"]
}`,
                },
                (0, descriptions_1.buildJsonSchemaExampleNotice)({
                    showExtraProps: {
                        '@version': [{ _cnd: { gte: 1.2 } }],
                    },
                }),
                {
                    ...descriptions_1.inputSchemaField,
                    default: `{
	"type": "object",
	"properties": {
		"state": {
			"type": "string"
		},
		"cities": {
			"type": "array",
			"items": {
				"type": "string"
			}
		}
	}
}`,
                },
                {
                    displayName: 'Attributes',
                    name: 'attributes',
                    placeholder: 'Add Attribute',
                    type: 'fixedCollection',
                    default: {},
                    displayOptions: {
                        show: {
                            schemaType: ['fromAttributes'],
                        },
                    },
                    typeOptions: {
                        multipleValues: true,
                    },
                    options: [
                        {
                            name: 'attributes',
                            displayName: 'Attribute List',
                            values: [
                                {
                                    displayName: 'Name',
                                    name: 'name',
                                    type: 'string',
                                    default: '',
                                    description: 'Attribute to extract',
                                    placeholder: 'e.g. company_name',
                                    required: true,
                                },
                                {
                                    displayName: 'Type',
                                    name: 'type',
                                    type: 'options',
                                    description: 'Data type of the attribute',
                                    required: true,
                                    options: [
                                        {
                                            name: 'Boolean',
                                            value: 'boolean',
                                        },
                                        {
                                            name: 'Date',
                                            value: 'date',
                                        },
                                        {
                                            name: 'Number',
                                            value: 'number',
                                        },
                                        {
                                            name: 'String',
                                            value: 'string',
                                        },
                                    ],
                                    default: 'string',
                                },
                                {
                                    displayName: 'Description',
                                    name: 'description',
                                    type: 'string',
                                    default: '',
                                    description: 'Describe your attribute',
                                    placeholder: 'Add description for the attribute',
                                    required: true,
                                },
                                {
                                    displayName: 'Required',
                                    name: 'required',
                                    type: 'boolean',
                                    default: false,
                                    description: 'Whether attribute is required',
                                    required: true,
                                },
                            ],
                        },
                    ],
                },
                {
                    displayName: 'Options',
                    name: 'options',
                    type: 'collection',
                    default: {},
                    placeholder: 'Add Option',
                    options: [
                        {
                            displayName: 'System Prompt Template',
                            name: 'systemPromptTemplate',
                            type: 'string',
                            default: constants_1.SYSTEM_PROMPT_TEMPLATE,
                            description: 'String to use directly as the system prompt template',
                            typeOptions: {
                                rows: 6,
                            },
                        },
                        (0, ai_utilities_1.getBatchingOptionFields)({
                            show: {
                                '@version': [{ _cnd: { gte: 1.1 } }],
                            },
                        }),
                    ],
                },
            ],
        };
    }
    async execute() {
        const items = this.getInputData();
        const llm = (await this.getInputConnectionData(n8n_workflow_1.NodeConnectionTypes.AiLanguageModel, 0));
        const schemaType = this.getNodeParameter('schemaType', 0, '');
        let parser;
        if (schemaType === 'fromAttributes') {
            const attributes = this.getNodeParameter('attributes.attributes', 0, []);
            if (attributes.length === 0) {
                throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'At least one attribute must be specified');
            }
            parser = output_parsers_1.OutputFixingParser.fromLLM(llm, output_parsers_1.StructuredOutputParser.fromZodSchema((0, helpers_1.makeZodSchemaFromAttributes)(attributes)));
        }
        else {
            let jsonSchema;
            if (schemaType === 'fromJson') {
                const jsonExample = this.getNodeParameter('jsonSchemaExample', 0, '');
                const jsonExampleAllFieldsRequired = this.getNode().typeVersion >= 1.2;
                jsonSchema = (0, schemaParsing_1.generateSchemaFromExample)(jsonExample, jsonExampleAllFieldsRequired);
            }
            else {
                const inputSchema = this.getNodeParameter('inputSchema', 0, '');
                jsonSchema = (0, n8n_workflow_1.jsonParse)(inputSchema);
            }
            const zodSchema = (0, schemaParsing_1.convertJsonSchemaToZod)(jsonSchema);
            parser = output_parsers_1.OutputFixingParser.fromLLM(llm, output_parsers_1.StructuredOutputParser.fromZodSchema(zodSchema));
        }
        const resultData = [];
        const batchSize = this.getNodeParameter('options.batching.batchSize', 0, 5);
        const delayBetweenBatches = this.getNodeParameter('options.batching.delayBetweenBatches', 0, 0);
        if (this.getNode().typeVersion >= 1.1 && batchSize >= 1) {
            for (let i = 0; i < items.length; i += batchSize) {
                const batch = items.slice(i, i + batchSize);
                const batchPromises = batch.map(async (_item, batchItemIndex) => {
                    const itemIndex = i + batchItemIndex;
                    return await (0, processItem_1.processItem)(this, itemIndex, llm, parser);
                });
                const batchResults = await Promise.allSettled(batchPromises);
                batchResults.forEach((response, index) => {
                    if (response.status === 'rejected') {
                        const error = response.reason;
                        if (this.continueOnFail()) {
                            resultData.push({
                                json: { error: error.message },
                                pairedItem: { item: i + index },
                            });
                            return;
                        }
                        else {
                            throw new n8n_workflow_1.NodeOperationError(this.getNode(), error.message);
                        }
                    }
                    const output = response.value;
                    resultData.push({ json: { output } });
                });
                if (i + batchSize < items.length && delayBetweenBatches > 0) {
                    await (0, n8n_workflow_1.sleep)(delayBetweenBatches);
                }
            }
        }
        else {
            for (let itemIndex = 0; itemIndex < items.length; itemIndex++) {
                try {
                    const output = await (0, processItem_1.processItem)(this, itemIndex, llm, parser);
                    resultData.push({ json: { output } });
                }
                catch (error) {
                    if (this.continueOnFail()) {
                        resultData.push({ json: { error: error.message }, pairedItem: { item: itemIndex } });
                        continue;
                    }
                    throw error;
                }
            }
        }
        return [resultData];
    }
}
exports.InformationExtractor = InformationExtractor;
//# sourceMappingURL=InformationExtractor.node.js.map