feat: implement interactive setup for primary/fallback models and Structured Output Parser
This commit is contained in:
parent
c52417a113
commit
a4b89d3691
1 changed files with 493 additions and 135 deletions
|
|
@ -1,5 +1,6 @@
|
|||
import * as fs from "fs";
|
||||
import * as path from "path";
|
||||
import * as readline from "readline";
|
||||
|
||||
// Helper to manually load .env file
|
||||
function loadEnv() {
|
||||
|
|
@ -23,7 +24,6 @@ loadEnv();
|
|||
|
||||
const N8N_HOST = process.env.N8N_HOST || "https://n8n.gaboggamer.online";
|
||||
const N8N_API_KEY = process.env.N8N_API_KEY;
|
||||
const DEEPSEEK_API_KEY = process.env.DEEPSEEK_API_KEY;
|
||||
const EMAIL_USER = process.env.EMAIL_USER;
|
||||
const EMAIL_PASSWORD = process.env.EMAIL_PASSWORD;
|
||||
const EMAIL_HOST = process.env.EMAIL_HOST;
|
||||
|
|
@ -36,6 +36,21 @@ if (!N8N_API_KEY) {
|
|||
process.exit(1);
|
||||
}
|
||||
|
||||
// Interactive prompt helper
|
||||
function askQuestion(query: string): Promise<string> {
|
||||
const rl = readline.createInterface({
|
||||
input: process.stdin,
|
||||
output: process.stdout,
|
||||
});
|
||||
|
||||
return new Promise((resolve) =>
|
||||
rl.question(query, (ans) => {
|
||||
rl.close();
|
||||
resolve(ans.trim());
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
// n8n request helper
|
||||
async function n8nRequest(endpoint: string, method: string = "GET", body?: any) {
|
||||
const response = await fetch(`${N8N_HOST}${endpoint}`, {
|
||||
|
|
@ -77,8 +92,140 @@ async function getOrCreateCredential(name: string, type: string, data: any) {
|
|||
}
|
||||
}
|
||||
|
||||
// LLM provider node configuration details
|
||||
interface ProviderConfig {
|
||||
nodeType: string;
|
||||
credentialType: string;
|
||||
credentialData: any;
|
||||
nodeParameters: any;
|
||||
}
|
||||
|
||||
function getProviderConfig(provider: string, apiKey: string, modelName: string): ProviderConfig {
|
||||
switch (provider) {
|
||||
case "1": // Deepseek (Native)
|
||||
return {
|
||||
nodeType: "@n8n/n8n-nodes-langchain.lmChatDeepSeek",
|
||||
credentialType: "deepSeekApi",
|
||||
credentialData: {
|
||||
apiKey,
|
||||
allowedHttpRequestDomains: "none",
|
||||
},
|
||||
nodeParameters: {
|
||||
model: modelName || "deepseek-chat",
|
||||
options: {},
|
||||
},
|
||||
};
|
||||
case "2": // OpenAI
|
||||
return {
|
||||
nodeType: "@n8n/n8n-nodes-langchain.lmChatOpenAi",
|
||||
credentialType: "openAiApi",
|
||||
credentialData: {
|
||||
apiKey,
|
||||
header: false,
|
||||
allowedHttpRequestDomains: "none",
|
||||
},
|
||||
nodeParameters: {
|
||||
model: modelName || "gpt-4o-mini",
|
||||
options: {},
|
||||
},
|
||||
};
|
||||
case "3": // Google Gemini
|
||||
return {
|
||||
nodeType: "@n8n/n8n-nodes-langchain.lmChatGoogleGemini",
|
||||
credentialType: "googlePalmApi",
|
||||
credentialData: {
|
||||
apiKey,
|
||||
host: "https://generativelanguage.googleapis.com",
|
||||
allowedHttpRequestDomains: "none",
|
||||
},
|
||||
nodeParameters: {
|
||||
model: modelName || "gemini-1.5-flash",
|
||||
options: {},
|
||||
},
|
||||
};
|
||||
case "4": // Anthropic
|
||||
return {
|
||||
nodeType: "@n8n/n8n-nodes-langchain.lmChatAnthropic",
|
||||
credentialType: "anthropicApi",
|
||||
credentialData: {
|
||||
apiKey,
|
||||
allowedHttpRequestDomains: "none",
|
||||
},
|
||||
nodeParameters: {
|
||||
model: modelName || "claude-3-5-sonnet-latest",
|
||||
options: {},
|
||||
},
|
||||
};
|
||||
default:
|
||||
throw new Error("Invalid provider chosen");
|
||||
}
|
||||
}
|
||||
|
||||
async function main() {
|
||||
console.log("Kickstarting n8n configuration with native integrations...");
|
||||
console.log("\n==================================================");
|
||||
console.log("Welcome to n8n Kickstart Interactive Setup");
|
||||
console.log("==================================================");
|
||||
|
||||
// 1. Ask for Primary Provider
|
||||
console.log("\nSelect Primary LLM Provider:");
|
||||
console.log("1. Deepseek (Native Node)");
|
||||
console.log("2. OpenAI (Standard)");
|
||||
console.log("3. Google Gemini");
|
||||
console.log("4. Anthropic");
|
||||
const primaryProviderChoice = await askQuestion("Enter choice (1-4) [default: 1]: ") || "1";
|
||||
|
||||
let defaultModel = "deepseek-chat";
|
||||
if (primaryProviderChoice === "2") defaultModel = "gpt-4o-mini";
|
||||
else if (primaryProviderChoice === "3") defaultModel = "gemini-1.5-flash";
|
||||
else if (primaryProviderChoice === "4") defaultModel = "claude-3-5-sonnet-latest";
|
||||
|
||||
const primaryModelName = await askQuestion(`Enter primary model name [default: ${defaultModel}]: `) || defaultModel;
|
||||
|
||||
let defaultKey = "";
|
||||
if (primaryProviderChoice === "1") defaultKey = process.env.DEEPSEEK_API_KEY || "";
|
||||
else if (primaryProviderChoice === "3") defaultKey = process.env.GEMINI_API_KEY || "";
|
||||
|
||||
const primaryApiKey = await askQuestion(`Enter API key [default: ${defaultKey ? "Loaded from .env" : "None"}]: `) || defaultKey;
|
||||
if (!primaryApiKey) {
|
||||
console.error("API Key is required.");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
// 2. Ask for Fallback Provider
|
||||
const configureFallback = (await askQuestion("\nDo you want to configure a Fallback LLM Model? (y/n) [default: n]: ") || "n").toLowerCase() === "y";
|
||||
let fallbackProviderChoice = "";
|
||||
let fallbackModelName = "";
|
||||
let fallbackApiKey = "";
|
||||
|
||||
if (configureFallback) {
|
||||
console.log("\nSelect Fallback LLM Provider:");
|
||||
console.log("1. Deepseek (Native Node)");
|
||||
console.log("2. OpenAI (Standard)");
|
||||
console.log("3. Google Gemini");
|
||||
console.log("4. Anthropic");
|
||||
fallbackProviderChoice = await askQuestion("Enter choice (1-4) [default: 3]: ") || "3";
|
||||
|
||||
let defaultFallbackModel = "gemini-1.5-flash";
|
||||
if (fallbackProviderChoice === "1") defaultFallbackModel = "deepseek-chat";
|
||||
else if (fallbackProviderChoice === "2") defaultFallbackModel = "gpt-4o-mini";
|
||||
else if (fallbackProviderChoice === "4") defaultFallbackModel = "claude-3-5-sonnet-latest";
|
||||
|
||||
fallbackModelName = await askQuestion(`Enter fallback model name [default: ${defaultFallbackModel}]: `) || defaultFallbackModel;
|
||||
|
||||
let defaultFallbackKey = "";
|
||||
if (fallbackProviderChoice === "1") defaultFallbackKey = process.env.DEEPSEEK_API_KEY || "";
|
||||
else if (fallbackProviderChoice === "3") defaultFallbackKey = process.env.GEMINI_API_KEY || "";
|
||||
|
||||
fallbackApiKey = await askQuestion(`Enter fallback API key [default: ${defaultFallbackKey ? "Loaded from .env" : "None"}]: `) || defaultFallbackKey;
|
||||
if (!fallbackApiKey) {
|
||||
console.error("Fallback API Key is required when fallback is enabled.");
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
console.log("\n==================================================");
|
||||
console.log("Setting up credentials on n8n server...");
|
||||
console.log("==================================================");
|
||||
|
||||
// 1. Manage IMAP Credentials
|
||||
const imapCredId = await getOrCreateCredential("Semillero2_IMAP", "imap", {
|
||||
|
|
@ -89,158 +236,369 @@ async function main() {
|
|||
secure: true,
|
||||
});
|
||||
|
||||
// 2. Manage OpenAI/Deepseek Credentials with explicit required validation flags
|
||||
const openAiCredId = await getOrCreateCredential("Semillero2_OpenAI", "openAiApi", {
|
||||
apiKey: DEEPSEEK_API_KEY,
|
||||
url: "https://api.deepseek.com/v1",
|
||||
header: false,
|
||||
allowedHttpRequestDomains: "none",
|
||||
});
|
||||
|
||||
// 3. Manage Supabase Credentials using modern keys structure (sb_secret_...)
|
||||
// 2. Manage Supabase Credentials using modern keys structure
|
||||
const supabaseCredId = await getOrCreateCredential("Semillero2_Supabase", "supabaseApi", {
|
||||
host: SUPABASE_URL,
|
||||
serviceRole: SUPABASE_SECRET_KEY,
|
||||
allowedHttpRequestDomains: "none",
|
||||
});
|
||||
|
||||
// 4. Define Workflow 3: Core AI Parsing Sub-workflow
|
||||
console.log("Deploying Workflow 3: Core AI Parsing Sub-workflow (Native AI & Supabase)...");
|
||||
const workflow3Definition = {
|
||||
name: "Semillero2: Core AI Parsing Sub-workflow",
|
||||
settings: {},
|
||||
nodes: [
|
||||
{
|
||||
parameters: {},
|
||||
id: "w3-trigger-id",
|
||||
name: "Execute Workflow Trigger",
|
||||
type: "n8n-nodes-base.executeWorkflowTrigger",
|
||||
typeVersion: 1,
|
||||
position: [250, 300],
|
||||
// 3. Manage Primary Model Credentials
|
||||
const primaryConfig = getProviderConfig(primaryProviderChoice, primaryApiKey, primaryModelName);
|
||||
const primaryCredId = await getOrCreateCredential("Semillero2_Primary_Model", primaryConfig.credentialType, primaryConfig.credentialData);
|
||||
|
||||
// 4. Manage Fallback Model Credentials (if enabled)
|
||||
let fallbackConfig: ProviderConfig | null = null;
|
||||
let fallbackCredId = "";
|
||||
if (configureFallback) {
|
||||
fallbackConfig = getProviderConfig(fallbackProviderChoice, fallbackApiKey, fallbackModelName);
|
||||
fallbackCredId = await getOrCreateCredential("Semillero2_Fallback_Model", fallbackConfig.credentialType, fallbackConfig.credentialData);
|
||||
}
|
||||
|
||||
// Define nodes dynamically
|
||||
console.log("\nBuilding workflow configurations...");
|
||||
|
||||
const parserNode = {
|
||||
parameters: {
|
||||
jsonSchema: "{\n \"type\": \"object\",\n \"properties\": {\n \"summary\": {\n \"type\": \"string\"\n },\n \"classification\": {\n \"type\": \"string\",\n \"enum\": [\"Qualified\", \"Unqualified\", \"Review\"]\n },\n \"suggestions\": {\n \"type\": \"array\",\n \"items\": {\n \"type\": \"string\"\n }\n },\n \"riskLevel\": {\n \"type\": \"string\",\n \"enum\": [\"Low\", \"Medium\", \"High\"]\n }\n },\n \"required\": [\"summary\", \"classification\", \"suggestions\", \"riskLevel\"]\n}",
|
||||
},
|
||||
id: "w3-parser-primary-id",
|
||||
name: "Structured Output Parser",
|
||||
type: "@n8n/n8n-nodes-langchain.outputParserStructured",
|
||||
typeVersion: 1,
|
||||
position: [680, 480],
|
||||
};
|
||||
|
||||
const primaryChainNode = {
|
||||
parameters: {
|
||||
promptType: "Define below", // Fixed casing as required!
|
||||
text: "={{ $json.text }}",
|
||||
systemMessage: "You are an AI recruitment assistant. Analyze the candidate's CV text. You MUST respond with a raw JSON object containing exactly these four keys:\n- summary: a brief profile summary.\n- classification: 'Qualified', 'Unqualified', or 'Review'.\n- suggestions: an array of recommendations for next steps.\n- riskLevel: 'Low', 'Medium', or 'High'.\n\nDo not include markdown code blocks or any text outside the JSON.",
|
||||
},
|
||||
id: "w3-chain-primary-id",
|
||||
name: "Basic LLM Chain (Primary)",
|
||||
type: "@n8n/n8n-nodes-langchain.chainLlm",
|
||||
typeVersion: 1.4,
|
||||
position: [480, 300],
|
||||
continueOnFail: configureFallback, // enable continue on fail only if fallback exists
|
||||
};
|
||||
|
||||
const primaryModelNode = {
|
||||
parameters: primaryConfig.nodeParameters,
|
||||
id: "w3-model-primary-id",
|
||||
name: "Primary Chat Model",
|
||||
type: primaryConfig.nodeType,
|
||||
typeVersion: 1,
|
||||
position: [480, 480],
|
||||
credentials: {
|
||||
[primaryConfig.credentialType]: {
|
||||
id: primaryCredId,
|
||||
name: "Semillero2_Primary_Model",
|
||||
},
|
||||
{
|
||||
parameters: {
|
||||
promptType: "defineBelow",
|
||||
text: "={{ $json.text }}",
|
||||
systemMessage: "You are an AI recruitment assistant. Analyze the candidate's CV text. You MUST respond with a raw JSON object containing exactly these four keys:\n- summary: a brief profile summary.\n- classification: 'Qualified', 'Unqualified', or 'Review'.\n- suggestions: an array of recommendations for next steps.\n- riskLevel: 'Low', 'Medium', or 'High'.\n\nDo not include markdown code blocks or any text outside the JSON.",
|
||||
},
|
||||
id: "w3-chain-id",
|
||||
name: "Basic LLM Chain",
|
||||
type: "@n8n/n8n-nodes-langchain.chainLlm",
|
||||
typeVersion: 1.4,
|
||||
position: [480, 300],
|
||||
},
|
||||
{
|
||||
parameters: {
|
||||
model: "deepseek-chat",
|
||||
options: {
|
||||
baseURL: "https://api.deepseek.com/v1",
|
||||
},
|
||||
},
|
||||
id: "w3-model-id",
|
||||
name: "OpenAI Chat Model",
|
||||
type: "@n8n/n8n-nodes-langchain.lmChatOpenAi",
|
||||
typeVersion: 1,
|
||||
position: [480, 480],
|
||||
credentials: {
|
||||
openAiApi: {
|
||||
id: openAiCredId,
|
||||
name: "Semillero2_OpenAI",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
parameters: {
|
||||
jsCode: `const content = $input.first().json.response.text;
|
||||
const cleanedText = content.replace(/\`\`\`json\\n?|\\n?\`\`\`/g, "").trim();
|
||||
const evaluation = JSON.parse(cleanedText);
|
||||
return [{
|
||||
},
|
||||
};
|
||||
|
||||
const parsePrimaryNode = {
|
||||
parameters: {
|
||||
jsCode: `return [{
|
||||
json: {
|
||||
name: $('Execute Workflow Trigger').item.json.name || "Unknown Candidate",
|
||||
email: $('Execute Workflow Trigger').item.json.email || "unknown@example.com",
|
||||
summary: evaluation.summary,
|
||||
seniority: evaluation.classification
|
||||
summary: $input.first().json.summary,
|
||||
seniority: $input.first().json.classification
|
||||
}
|
||||
}];`,
|
||||
},
|
||||
id: "w3-parse-id",
|
||||
name: "Parse LLM Response",
|
||||
type: "n8n-nodes-base.code",
|
||||
typeVersion: 2,
|
||||
position: [700, 300],
|
||||
},
|
||||
{
|
||||
parameters: {
|
||||
operation: "insert",
|
||||
table: "candidates",
|
||||
options: {},
|
||||
},
|
||||
id: "w3-supabase-id",
|
||||
name: "Insert Candidate to Supabase",
|
||||
type: "n8n-nodes-base.supabase",
|
||||
typeVersion: 1,
|
||||
position: [920, 300],
|
||||
credentials: {
|
||||
supabaseApi: {
|
||||
id: supabaseCredId,
|
||||
name: "Semillero2_Supabase",
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
connections: {
|
||||
"Execute Workflow Trigger": {
|
||||
main: [
|
||||
[
|
||||
{
|
||||
node: "Basic LLM Chain",
|
||||
type: "main",
|
||||
index: 0,
|
||||
},
|
||||
],
|
||||
],
|
||||
},
|
||||
"OpenAI Chat Model": {
|
||||
ai_languageModel: [
|
||||
[
|
||||
{
|
||||
node: "Basic LLM Chain",
|
||||
type: "ai_languageModel",
|
||||
index: 0,
|
||||
},
|
||||
],
|
||||
],
|
||||
},
|
||||
"Basic LLM Chain": {
|
||||
main: [
|
||||
[
|
||||
{
|
||||
node: "Parse LLM Response",
|
||||
type: "main",
|
||||
index: 0,
|
||||
},
|
||||
],
|
||||
],
|
||||
},
|
||||
"Parse LLM Response": {
|
||||
main: [
|
||||
[
|
||||
{
|
||||
node: "Insert Candidate to Supabase",
|
||||
type: "main",
|
||||
index: 0,
|
||||
},
|
||||
],
|
||||
],
|
||||
},
|
||||
id: "w3-parse-primary-id",
|
||||
name: "Parse Primary Response",
|
||||
type: "n8n-nodes-base.code",
|
||||
typeVersion: 2,
|
||||
position: [900, 200],
|
||||
};
|
||||
|
||||
const supabaseInsertNode = {
|
||||
parameters: {
|
||||
operation: "insert",
|
||||
table: "candidates",
|
||||
options: {},
|
||||
},
|
||||
id: "w3-supabase-id",
|
||||
name: "Insert Candidate to Supabase",
|
||||
type: "n8n-nodes-base.supabase",
|
||||
typeVersion: 1,
|
||||
position: [1150, 300],
|
||||
credentials: {
|
||||
supabaseApi: {
|
||||
id: supabaseCredId,
|
||||
name: "Semillero2_Supabase",
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
// Build the complete list of nodes and connections for Workflow 3
|
||||
const w3Nodes: any[] = [
|
||||
{
|
||||
parameters: {},
|
||||
id: "w3-trigger-id",
|
||||
name: "Execute Workflow Trigger",
|
||||
type: "n8n-nodes-base.executeWorkflowTrigger",
|
||||
typeVersion: 1,
|
||||
position: [250, 300],
|
||||
},
|
||||
primaryChainNode,
|
||||
primaryModelNode,
|
||||
parserNode,
|
||||
supabaseInsertNode,
|
||||
];
|
||||
|
||||
const w3Connections: any = {
|
||||
"Execute Workflow Trigger": {
|
||||
main: [
|
||||
[
|
||||
{
|
||||
node: "Basic LLM Chain (Primary)",
|
||||
type: "main",
|
||||
index: 0,
|
||||
},
|
||||
],
|
||||
],
|
||||
},
|
||||
"Primary Chat Model": {
|
||||
ai_languageModel: [
|
||||
[
|
||||
{
|
||||
node: "Basic LLM Chain (Primary)",
|
||||
type: "ai_languageModel",
|
||||
index: 0,
|
||||
},
|
||||
],
|
||||
],
|
||||
},
|
||||
"Structured Output Parser": {
|
||||
outputParser: [
|
||||
[
|
||||
{
|
||||
node: "Basic LLM Chain (Primary)",
|
||||
type: "outputParser",
|
||||
index: 0,
|
||||
},
|
||||
],
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
if (configureFallback && fallbackConfig) {
|
||||
console.log("Configuring error handling and fallback route...");
|
||||
|
||||
const checkErrorNode = {
|
||||
parameters: {
|
||||
conditions: {
|
||||
boolean: [
|
||||
{
|
||||
value1: "={{ $json.hasOwnProperty('error') }}",
|
||||
value2: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
id: "w3-check-error-id",
|
||||
name: "Check Primary Error",
|
||||
type: "n8n-nodes-base.if",
|
||||
typeVersion: 2.2,
|
||||
position: [680, 200],
|
||||
};
|
||||
|
||||
const fallbackChainNode = {
|
||||
parameters: {
|
||||
promptType: "Define below",
|
||||
text: "={{ $('Execute Workflow Trigger').item.json.text }}",
|
||||
systemMessage: "You are an AI recruitment assistant. Analyze the candidate's CV text. You MUST respond with a raw JSON object containing exactly these four keys:\n- summary: a brief profile summary.\n- classification: 'Qualified', 'Unqualified', or 'Review'.\n- suggestions: an array of recommendations for next steps.\n- riskLevel: 'Low', 'Medium', or 'High'.\n\nDo not include markdown code blocks or any text outside the JSON.",
|
||||
},
|
||||
id: "w3-chain-fallback-id",
|
||||
name: "Basic LLM Chain (Fallback)",
|
||||
type: "@n8n/n8n-nodes-langchain.chainLlm",
|
||||
typeVersion: 1.4,
|
||||
position: [900, 400],
|
||||
};
|
||||
|
||||
const fallbackModelNode = {
|
||||
parameters: fallbackConfig.nodeParameters,
|
||||
id: "w3-model-fallback-id",
|
||||
name: "Fallback Chat Model",
|
||||
type: fallbackConfig.nodeType,
|
||||
typeVersion: 1,
|
||||
position: [900, 580],
|
||||
credentials: {
|
||||
[fallbackConfig.credentialType]: {
|
||||
id: fallbackCredId,
|
||||
name: "Semillero2_Fallback_Model",
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const parserFallbackNode = {
|
||||
parameters: {
|
||||
jsonSchema: "{\n \"type\": \"object\",\n \"properties\": {\n \"summary\": {\n \"type\": \"string\"\n },\n \"classification\": {\n \"type\": \"string\",\n \"enum\": [\"Qualified\", \"Unqualified\", \"Review\"]\n },\n \"suggestions\": {\n \"type\": \"array\",\n \"items\": {\n \"type\": \"string\"\n }\n },\n \"riskLevel\": {\n \"type\": \"string\",\n \"enum\": [\"Low\", \"Medium\", \"High\"]\n }\n },\n \"required\": [\"summary\", \"classification\", \"suggestions\", \"riskLevel\"]\n}",
|
||||
},
|
||||
id: "w3-parser-fallback-id",
|
||||
name: "Structured Output Parser (Fallback)",
|
||||
type: "@n8n/n8n-nodes-langchain.outputParserStructured",
|
||||
typeVersion: 1,
|
||||
position: [1050, 580],
|
||||
};
|
||||
|
||||
const parseFallbackNode = {
|
||||
parameters: {
|
||||
jsCode: `return [{
|
||||
json: {
|
||||
name: $('Execute Workflow Trigger').item.json.name || "Unknown Candidate",
|
||||
email: $('Execute Workflow Trigger').item.json.email || "unknown@example.com",
|
||||
summary: $input.first().json.summary,
|
||||
seniority: $input.first().json.classification
|
||||
}
|
||||
}];`,
|
||||
},
|
||||
id: "w3-parse-fallback-id",
|
||||
name: "Parse Fallback Response",
|
||||
type: "n8n-nodes-base.code",
|
||||
typeVersion: 2,
|
||||
position: [1120, 400],
|
||||
};
|
||||
|
||||
w3Nodes.push(checkErrorNode, parsePrimaryNode, fallbackChainNode, fallbackModelNode, parserFallbackNode, parseFallbackNode);
|
||||
|
||||
// Wire fallback connections
|
||||
w3Connections["Basic LLM Chain (Primary)"] = {
|
||||
main: [
|
||||
[
|
||||
{
|
||||
node: "Check Primary Error",
|
||||
type: "main",
|
||||
index: 0,
|
||||
},
|
||||
],
|
||||
],
|
||||
};
|
||||
|
||||
w3Connections["Check Primary Error"] = {
|
||||
main: [
|
||||
[
|
||||
{
|
||||
node: "Basic LLM Chain (Fallback)",
|
||||
type: "main",
|
||||
index: 0,
|
||||
},
|
||||
], // Output 0 (true -> Error happened)
|
||||
[
|
||||
{
|
||||
node: "Parse Primary Response",
|
||||
type: "main",
|
||||
index: 0,
|
||||
},
|
||||
], // Output 1 (false -> Success)
|
||||
],
|
||||
};
|
||||
|
||||
w3Connections["Fallback Chat Model"] = {
|
||||
ai_languageModel: [
|
||||
[
|
||||
{
|
||||
node: "Basic LLM Chain (Fallback)",
|
||||
type: "ai_languageModel",
|
||||
index: 0,
|
||||
},
|
||||
],
|
||||
],
|
||||
};
|
||||
|
||||
w3Connections["Structured Output Parser (Fallback)"] = {
|
||||
outputParser: [
|
||||
[
|
||||
{
|
||||
node: "Basic LLM Chain (Fallback)",
|
||||
type: "outputParser",
|
||||
index: 0,
|
||||
},
|
||||
],
|
||||
],
|
||||
};
|
||||
|
||||
w3Connections["Basic LLM Chain (Fallback)"] = {
|
||||
main: [
|
||||
[
|
||||
{
|
||||
node: "Parse Fallback Response",
|
||||
type: "main",
|
||||
index: 0,
|
||||
},
|
||||
],
|
||||
],
|
||||
};
|
||||
|
||||
w3Connections["Parse Primary Response"] = {
|
||||
main: [
|
||||
[
|
||||
{
|
||||
node: "Insert Candidate to Supabase",
|
||||
type: "main",
|
||||
index: 0,
|
||||
},
|
||||
],
|
||||
],
|
||||
};
|
||||
|
||||
w3Connections["Parse Fallback Response"] = {
|
||||
main: [
|
||||
[
|
||||
{
|
||||
node: "Insert Candidate to Supabase",
|
||||
type: "main",
|
||||
index: 0,
|
||||
},
|
||||
],
|
||||
],
|
||||
};
|
||||
} else {
|
||||
// If no fallback, wire directly Primary Chain -> Parse Primary Response -> Supabase
|
||||
w3Nodes.push(parsePrimaryNode);
|
||||
w3Connections["Basic LLM Chain (Primary)"] = {
|
||||
main: [
|
||||
[
|
||||
{
|
||||
node: "Parse Primary Response",
|
||||
type: "main",
|
||||
index: 0,
|
||||
},
|
||||
],
|
||||
],
|
||||
};
|
||||
w3Connections["Parse Primary Response"] = {
|
||||
main: [
|
||||
[
|
||||
{
|
||||
node: "Insert Candidate to Supabase",
|
||||
type: "main",
|
||||
index: 0,
|
||||
},
|
||||
],
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
// 5. Deploy Workflow 3
|
||||
console.log("\nDeploying Workflow 3: Core AI Parsing Sub-workflow...");
|
||||
const workflow3Definition = {
|
||||
name: "Semillero2: Core AI Parsing Sub-workflow",
|
||||
settings: {},
|
||||
nodes: w3Nodes,
|
||||
connections: w3Connections,
|
||||
};
|
||||
|
||||
const w3Result = await n8nRequest("/api/v1/workflows", "POST", workflow3Definition);
|
||||
const w3Id = w3Result.id;
|
||||
console.log(`Workflow 3 deployed successfully (ID: ${w3Id})`);
|
||||
|
||||
// 5. Define Workflow 1: The API Gateway (Web UI Ingestion)
|
||||
// 6. Define Workflow 1: The API Gateway (Web UI Ingestion)
|
||||
console.log("Deploying Workflow 1: The API Gateway...");
|
||||
const workflow1Definition = {
|
||||
name: "Semillero2: API Gateway (Web UI Ingestion)",
|
||||
|
|
@ -345,7 +703,7 @@ return [{
|
|||
console.log(`Workflow 1 deployed successfully (ID: ${w1Id})`);
|
||||
console.log(`Webhook URL: ${webhookPath}`);
|
||||
|
||||
// 6. Define Workflow 2: Email Ingestion Listener
|
||||
// 7. Define Workflow 2: Email Ingestion Listener
|
||||
console.log("Deploying Workflow 2: Email Ingestion Listener...");
|
||||
const workflow2Definition = {
|
||||
name: "Semillero2: Email Ingestion Listener",
|
||||
|
|
|
|||
Loading…
Reference in a new issue