Implement prompt optimization features across workflow components

- Integrated a new prompt optimization service to enhance AI task node prompts, improving context-awareness and domain specificity.
- Updated NodeConfiguration component to include a button for optimizing prompts, displaying results for user review and application.
- Enhanced workflow generation logic to utilize optimized prompts, ensuring better performance in AI analysis tasks.
- Refactored existing prompt generation methods to leverage the new prompt optimizer, streamlining the process for various data types and tasks.
- Added detailed context and instructions for AI tasks, improving the overall user experience and output quality.
This commit is contained in:
Nikhil-Doye
2025-10-18 23:48:46 -04:00
parent 6279d5914f
commit 8dd1a9e042
5 changed files with 1106 additions and 43 deletions
+200 -9
View File
@@ -1,7 +1,9 @@
import React from "react";
import React, { useState } from "react";
import { NodeData } from "../types";
import { useWorkflowStore } from "../store/workflowStore";
import { X, Settings } from "lucide-react";
import { X, Settings, Sparkles } from "lucide-react";
import { promptOptimizer } from "../services/promptOptimizer";
import { callOpenAI } from "../services/openaiService";
interface NodeConfigurationProps {
nodeId: string;
@@ -192,6 +194,8 @@ export const NodeConfiguration: React.FC<NodeConfigurationProps> = ({
}) => {
const { updateNode, currentWorkflow } = useWorkflowStore();
const config = nodeTypeConfigs[data.type];
const [isOptimizing, setIsOptimizing] = useState(false);
const [optimizationResult, setOptimizationResult] = useState<string>("");
// Get the latest node data from the store to ensure we have the most up-to-date config
const currentNode = currentWorkflow?.nodes.find((node) => node.id === nodeId);
@@ -210,19 +214,163 @@ export const NodeConfiguration: React.FC<NodeConfigurationProps> = ({
updateNode(nodeId, { label });
};
const handleOptimizePrompt = async () => {
if (!currentData.config.prompt) {
alert("Please enter a prompt first");
return;
}
setIsOptimizing(true);
setOptimizationResult("");
try {
// Extract intent from the prompt itself
const prompt = currentData.config.prompt;
const entities = {
aiTasks: prompt.toLowerCase().includes("analyze")
? ["analyze"]
: prompt.toLowerCase().includes("summarize")
? ["summarize"]
: prompt.toLowerCase().includes("extract")
? ["extract"]
: prompt.toLowerCase().includes("classify")
? ["classify"]
: prompt.toLowerCase().includes("generate")
? ["generate"]
: ["process"],
dataTypes: prompt.toLowerCase().includes("resume")
? ["resume"]
: prompt.toLowerCase().includes("document")
? ["document"]
: prompt.toLowerCase().includes("text")
? ["text"]
: ["text"],
urls: [],
complexity: "medium",
};
// Create mock node context
const nodeContext = {
dataType: "text",
previousNodes: [],
intent: "AI_ANALYSIS",
domain: prompt.toLowerCase().includes("resume")
? "jobApplication"
: prompt.toLowerCase().includes("financial")
? "financial"
: prompt.toLowerCase().includes("legal")
? "legal"
: "general",
workflowType: "ai_analysis",
availableData: new Map(),
};
// Generate optimized prompt using the prompt optimizer
const optimizedPrompt = promptOptimizer.generateOptimizedPrompt(
prompt,
entities,
nodeContext,
new Map()
);
// Make DeepSeek API call to further optimize the prompt
const apiResponse = await callOpenAI(
`You are a prompt optimization expert. Your task is to optimize the given prompt for better AI performance.
IMPORTANT: Return ONLY the optimized prompt. Do not include any explanations, comments, or additional text. Just the optimized prompt itself.
Original Prompt: ${prompt}
Optimized Template: ${optimizedPrompt}
Return only the optimized prompt:`,
{
model: "deepseek-chat",
temperature: 0.7,
maxTokens: 1000,
}
);
// Clean up the response to ensure we only get the optimized prompt
let cleanedResult = apiResponse.content.trim();
// Remove common prefixes that might be added by the AI
const prefixesToRemove = [
"Optimized Prompt:",
"Here's the optimized prompt:",
"The optimized prompt is:",
"Optimized version:",
"Here is the optimized prompt:",
"Optimized prompt:",
"Here's the improved prompt:",
"Improved prompt:",
"Here is the improved prompt:",
"The improved prompt is:",
"Here's the enhanced prompt:",
"Enhanced prompt:",
"Here is the enhanced prompt:",
"The enhanced prompt is:",
];
for (const prefix of prefixesToRemove) {
if (cleanedResult.toLowerCase().startsWith(prefix.toLowerCase())) {
cleanedResult = cleanedResult.substring(prefix.length).trim();
}
}
// Remove any quotes that might wrap the prompt
if (
(cleanedResult.startsWith('"') && cleanedResult.endsWith('"')) ||
(cleanedResult.startsWith("'") && cleanedResult.endsWith("'"))
) {
cleanedResult = cleanedResult.slice(1, -1).trim();
}
setOptimizationResult(cleanedResult);
} catch (error) {
console.error("Error optimizing prompt:", error);
setOptimizationResult("Error optimizing prompt. Please try again.");
} finally {
setIsOptimizing(false);
}
};
const applyOptimizedPrompt = () => {
if (optimizationResult) {
handleConfigChange("prompt", optimizationResult);
setOptimizationResult("");
}
};
const renderField = (field: any) => {
const value = currentData.config[field.key] || field.defaultValue || "";
switch (field.type) {
case "textarea":
return (
<textarea
value={value}
onChange={(e) => handleConfigChange(field.key, e.target.value)}
placeholder={field.placeholder}
className="w-full p-2 border border-gray-300 rounded-md focus:ring-2 focus:ring-primary-500 focus:border-transparent"
rows={3}
/>
<div className="space-y-2">
<textarea
value={value}
onChange={(e) => handleConfigChange(field.key, e.target.value)}
placeholder={field.placeholder}
className="w-full p-2 border border-gray-300 rounded-md focus:ring-2 focus:ring-primary-500 focus:border-transparent"
rows={3}
/>
{data.type === "llmTask" && field.key === "prompt" && (
<div className="flex items-center space-x-2">
<button
onClick={handleOptimizePrompt}
disabled={isOptimizing || !currentData.config.prompt}
className="flex items-center space-x-2 px-3 py-1.5 bg-gradient-to-r from-purple-500 to-pink-500 text-white text-sm font-medium rounded-md hover:from-purple-600 hover:to-pink-600 disabled:opacity-50 disabled:cursor-not-allowed transition-all duration-200 shadow-sm"
>
<Sparkles className="w-4 h-4" />
<span>
{isOptimizing ? "Optimizing..." : "Optimize Prompt"}
</span>
</button>
</div>
)}
</div>
);
case "select":
if (field.multiple) {
@@ -350,6 +498,49 @@ export const NodeConfiguration: React.FC<NodeConfigurationProps> = ({
{renderField(field)}
</div>
))}
{/* Optimization Result Display */}
{data.type === "llmTask" && optimizationResult && (
<div className="mt-4 p-4 bg-gradient-to-r from-purple-50 to-pink-50 border border-purple-200 rounded-lg">
<div className="flex items-center space-x-2 mb-3">
<Sparkles className="w-4 h-4 text-purple-600" />
<h4 className="text-sm font-semibold text-purple-800">
Optimized Prompt Preview
</h4>
<span className="px-2 py-1 bg-purple-100 text-purple-700 text-xs rounded-full">
Preview
</span>
</div>
<div className="bg-white p-4 rounded-md border border-purple-100 shadow-sm">
<div className="mb-2 text-xs text-gray-500 font-medium">
Optimized Prompt:
</div>
<pre className="text-sm text-gray-800 whitespace-pre-wrap font-mono leading-relaxed bg-gray-50 p-3 rounded border">
{optimizationResult}
</pre>
</div>
<div className="mt-3 flex items-center justify-between">
<div className="text-xs text-purple-600">
Review the optimized prompt above and click "Apply" to replace
your current prompt.
</div>
<div className="flex space-x-2">
<button
onClick={() => setOptimizationResult("")}
className="px-3 py-1 text-xs text-gray-600 hover:text-gray-800 hover:bg-gray-100 rounded transition-colors"
>
Cancel
</button>
<button
onClick={applyOptimizedPrompt}
className="px-3 py-1 bg-green-500 text-white text-xs font-medium rounded hover:bg-green-600 transition-colors"
>
Apply Optimized Prompt
</button>
</div>
</div>
</div>
)}
</div>
<div className="flex justify-end space-x-2 p-4 border-t border-gray-200">
+127 -3
View File
@@ -275,14 +275,36 @@ Respond with JSON:
}
/**
* Generate workflow structure using LLM
* Generate workflow structure using LLM with optimized prompts
*/
private async generateWorkflowStructureWithLLM(
userInput: string,
intent: IntentClassification,
entities: EntityExtraction
): Promise<WorkflowStructure> {
const prompt = `
// Import the prompt optimizer
const { promptOptimizer } = require("./promptOptimizer");
// Create context for workflow generation
const workflowContext = {
dataType: this.determineWorkflowDataType(entities),
previousNodes: [],
intent: intent.intent,
domain: this.determineWorkflowDomain(userInput, entities),
workflowType: this.determineWorkflowType(intent, entities),
availableData: new Map(),
};
// Generate optimized prompt for workflow generation
const optimizedPrompt = promptOptimizer.generateOptimizedPrompt(
userInput,
entities,
workflowContext,
workflowContext.availableData
);
const prompt = `${optimizedPrompt}
You are an AI workflow designer. Analyze the user's request and create a comprehensive workflow structure.
User Request: "${userInput}"
@@ -300,10 +322,11 @@ Instructions:
1. Understand the user's goal and break it down into logical steps
2. Create a workflow that accomplishes their request
3. Use appropriate node types for each step
4. Configure nodes with realistic settings
4. Configure nodes with realistic settings and optimized prompts
5. Connect nodes logically with proper data flow
6. Use variable substitution ({{nodeId.output}}) to pass data between nodes
7. Make the workflow practical and executable
8. For LLM nodes, use context-aware, domain-specific prompts
For job application workflows, consider:
- Resume analysis and skill extraction
@@ -628,6 +651,107 @@ Respond with valid JSON only:
hitRate: 0.8, // Placeholder - would track actual hit rate
};
}
/**
* Determine workflow data type from entities
*/
private determineWorkflowDataType(entities: EntityExtraction): string {
if (entities.urls?.length > 0) return "url";
if (entities.dataTypes?.includes("json")) return "json";
if (entities.dataTypes?.includes("csv")) return "csv";
if (entities.dataTypes?.includes("pdf")) return "pdf";
if (
entities.dataTypes?.includes("resume") ||
entities.dataTypes?.includes("cv")
)
return "text";
return "text";
}
/**
* Determine workflow domain from user input and entities
*/
private determineWorkflowDomain(
userInput: string,
entities: EntityExtraction
): string {
const input = userInput.toLowerCase();
if (
entities.dataTypes?.includes("resume") ||
entities.dataTypes?.includes("cv") ||
input.includes("resume") ||
input.includes("job") ||
input.includes("career")
) {
return "jobApplication";
}
if (
entities.dataTypes?.includes("financial") ||
input.includes("financial") ||
input.includes("revenue") ||
input.includes("profit")
) {
return "financial";
}
if (
entities.dataTypes?.includes("legal") ||
input.includes("legal") ||
input.includes("contract") ||
input.includes("agreement")
) {
return "legal";
}
if (
entities.dataTypes?.includes("medical") ||
input.includes("medical") ||
input.includes("health") ||
input.includes("patient")
) {
return "medical";
}
if (
entities.dataTypes?.includes("technical") ||
input.includes("technical") ||
input.includes("code") ||
input.includes("software")
) {
return "technical";
}
if (
input.includes("content") ||
input.includes("marketing") ||
input.includes("seo")
) {
return "contentAnalysis";
}
return "general";
}
/**
* Determine workflow type from intent and entities
*/
private determineWorkflowType(
intent: IntentClassification,
entities: EntityExtraction
): string {
if (intent.intent === "WEB_SCRAPING") return "web_scraping";
if (intent.intent === "AI_ANALYSIS") return "ai_analysis";
if (intent.intent === "DATA_PROCESSING") return "data_processing";
if (intent.intent === "SEARCH_AND_RETRIEVAL") return "search_retrieval";
if (
entities.dataTypes?.includes("resume") ||
entities.dataTypes?.includes("cv")
)
return "job_application";
return "general";
}
}
// Export singleton instance
+593
View File
@@ -0,0 +1,593 @@
/**
* Advanced Prompt Optimization Service
* Generates context-aware, domain-specific prompts for AI Task Nodes
*/
export interface NodeContext {
dataType: string;
previousNodes: string[];
intent: string;
domain?: string;
workflowType?: string;
availableData: Map<string, any>;
}
export interface PromptPerformance {
quality: number; // 1-10 scale
relevance: number; // 1-10 scale
completeness: number; // 1-10 scale
userSatisfaction?: number; // 1-10 scale
executionTime?: number; // milliseconds
}
export interface PromptRefinement {
type:
| "add_context"
| "add_examples"
| "improve_instructions"
| "adjust_format";
description: string;
implementation: string;
}
export interface DomainPromptTemplate {
role: string;
context: string;
instructions: string;
examples?: string[];
outputFormat: string;
chainOfThought?: boolean;
}
export class PromptOptimizer {
private promptHistory = new Map<string, PromptPerformance>();
private domainTemplates = new Map<string, DomainPromptTemplate>();
private fewShotExamples = new Map<string, any[]>();
constructor() {
this.initializeDomainTemplates();
this.initializeFewShotExamples();
}
/**
* Generate an optimized prompt for an AI Task Node
*/
generateOptimizedPrompt(
userIntent: string,
entities: any,
nodeContext: NodeContext,
availableData: Map<string, any>
): string {
const promptBuilder = new PromptBuilder();
// Determine the appropriate domain and task type
const domain = this.determineDomain(userIntent, entities, nodeContext);
const taskType = this.determineTaskType(userIntent, entities);
// Add role and context
const role = this.determineRole(userIntent, entities, domain);
promptBuilder.addRole(role);
// Add domain-specific context
const context = this.buildContext(
userIntent,
entities,
nodeContext,
domain
);
promptBuilder.addContext(context);
// Add specific instructions
const instructions = this.generateInstructions(
userIntent,
entities,
taskType,
domain
);
promptBuilder.addInstructions(instructions);
// Add few-shot examples if available
const examples = this.getRelevantExamples(taskType, domain);
if (examples.length > 0) {
promptBuilder.addExamples(examples);
}
// Add chain-of-thought if needed
if (this.shouldUseChainOfThought(taskType, entities)) {
promptBuilder.addChainOfThought();
}
// Add output format requirements
const outputFormat = this.determineOutputFormat(
userIntent,
entities,
taskType
);
promptBuilder.addOutputFormat(outputFormat);
// Add available data context
const dataContext = this.buildDataContext(availableData, nodeContext);
promptBuilder.addDataContext(dataContext);
return promptBuilder.build();
}
/**
* Determine the appropriate domain for the prompt
*/
private determineDomain(
userIntent: string,
entities: any,
nodeContext: NodeContext
): string {
// Check for specific domain indicators
if (
entities.dataTypes?.includes("resume") ||
entities.dataTypes?.includes("cv")
) {
return "jobApplication";
}
if (
entities.dataTypes?.includes("financial") ||
userIntent.toLowerCase().includes("financial")
) {
return "financial";
}
if (
entities.dataTypes?.includes("legal") ||
userIntent.toLowerCase().includes("legal")
) {
return "legal";
}
if (
entities.dataTypes?.includes("medical") ||
userIntent.toLowerCase().includes("medical")
) {
return "medical";
}
if (
entities.dataTypes?.includes("technical") ||
userIntent.toLowerCase().includes("technical")
) {
return "technical";
}
if (nodeContext.workflowType === "content_analysis") {
return "contentAnalysis";
}
return "general";
}
/**
* Determine the specific task type
*/
private determineTaskType(userIntent: string, entities: any): string {
const tasks = entities.aiTasks || [];
if (tasks.includes("summarize")) return "summarize";
if (tasks.includes("analyze")) return "analyze";
if (tasks.includes("extract")) return "extract";
if (tasks.includes("classify")) return "classify";
if (tasks.includes("generate")) return "generate";
if (tasks.includes("translate")) return "translate";
if (tasks.includes("sentiment")) return "sentiment";
if (tasks.includes("compare")) return "compare";
// Fallback based on intent
if (userIntent.toLowerCase().includes("summarize")) return "summarize";
if (userIntent.toLowerCase().includes("analyze")) return "analyze";
if (userIntent.toLowerCase().includes("extract")) return "extract";
return "process";
}
/**
* Determine the appropriate role for the AI
*/
private determineRole(
userIntent: string,
entities: any,
domain: string
): string {
const domainRoles: Record<string, string> = {
jobApplication: "expert career counselor and resume analyst",
financial: "senior financial analyst and investment advisor",
legal: "experienced legal counsel and document analyst",
medical: "medical professional and clinical analyst",
technical: "senior software engineer and technical architect",
contentAnalysis: "content strategist and digital marketing expert",
general: "expert data analyst and business consultant",
};
return domainRoles[domain] || domainRoles.general;
}
/**
* Build context-aware information
*/
private buildContext(
userIntent: string,
entities: any,
nodeContext: NodeContext,
domain: string
): string {
const contextParts = [];
// Add data type context
if (nodeContext.dataType) {
contextParts.push(`Data Type: ${nodeContext.dataType}`);
}
// Add domain-specific context
if (domain !== "general") {
contextParts.push(`Domain: ${domain}`);
}
// Add workflow context
if (nodeContext.previousNodes.length > 0) {
contextParts.push(
`Previous Processing: ${nodeContext.previousNodes.join(" → ")}`
);
}
// Add entity context
if (entities.urls?.length > 0) {
contextParts.push(`Source URLs: ${entities.urls.join(", ")}`);
}
if (entities.dataTypes?.length > 0) {
contextParts.push(`Data Types: ${entities.dataTypes.join(", ")}`);
}
return contextParts.join("\n");
}
/**
* Generate specific instructions based on task type and domain
*/
private generateInstructions(
userIntent: string,
entities: any,
taskType: string,
domain: string
): string {
const template = this.domainTemplates.get(domain);
if (template) {
return template.instructions;
}
// Fallback to task-specific instructions
const taskInstructions: Record<string, string> = {
summarize:
"Provide a clear, concise summary that captures the key points and main insights.",
analyze:
"Conduct a thorough analysis, identifying patterns, trends, and actionable insights.",
extract:
"Extract specific information systematically, organizing it in a structured format.",
classify:
"Categorize the content accurately, providing clear reasoning for each classification.",
generate:
"Create high-quality content that meets the specified requirements and objectives.",
translate:
"Provide accurate, contextually appropriate translations while preserving meaning.",
sentiment:
"Analyze emotional tone and sentiment with specific evidence and confidence levels.",
compare:
"Perform detailed comparisons highlighting similarities, differences, and implications.",
process:
"Process the data systematically to extract maximum value and insights.",
};
return taskInstructions[taskType] || taskInstructions.process;
}
/**
* Get relevant few-shot examples
*/
private getRelevantExamples(taskType: string, domain: string): any[] {
const key = `${domain}_${taskType}`;
return (
this.fewShotExamples.get(key) || this.fewShotExamples.get(taskType) || []
);
}
/**
* Determine if chain-of-thought prompting should be used
*/
private shouldUseChainOfThought(taskType: string, entities: any): boolean {
const complexTasks = ["analyze", "compare", "classify", "sentiment"];
return complexTasks.includes(taskType) || entities.complexity === "high";
}
/**
* Determine output format requirements
*/
private determineOutputFormat(
userIntent: string,
entities: any,
taskType: string
): string {
if (entities.outputFormat) {
return entities.outputFormat;
}
const formatPreferences: Record<string, string> = {
summarize:
"Provide a clear, structured summary with key points highlighted.",
analyze:
"Present findings in a structured format with clear sections and actionable insights.",
extract:
"Organize extracted information in a logical, easy-to-read format.",
classify:
"Provide classifications with clear categories and supporting evidence.",
generate:
"Format content appropriately for the intended audience and purpose.",
sentiment:
"Include sentiment scores, confidence levels, and supporting evidence.",
compare:
"Present comparisons in a clear, side-by-side format with conclusions.",
process: "Structure the output for maximum clarity and usability.",
};
return formatPreferences[taskType] || formatPreferences.process;
}
/**
* Build data context from available node outputs
*/
private buildDataContext(
availableData: Map<string, any>,
nodeContext: NodeContext
): string {
if (availableData.size === 0) {
return "Input data: {{input.output}}";
}
const dataDescriptions = [];
for (const [nodeId, data] of availableData) {
if (data.output) {
dataDescriptions.push(
`${nodeId}: ${
typeof data.output === "string"
? data.output.substring(0, 100) + "..."
: "Complex data object"
}`
);
}
}
return `Available data:\n${dataDescriptions.join(
"\n"
)}\n\nPrimary input: {{input.output}}`;
}
/**
* Initialize domain-specific templates
*/
private initializeDomainTemplates(): void {
// Job Application Domain
this.domainTemplates.set("jobApplication", {
role: "expert career counselor and resume analyst",
context:
"You are analyzing job application materials to provide career guidance and optimization recommendations.",
instructions: `When analyzing resumes and job applications:
1. Identify key skills, experience, and achievements
2. Assess alignment with job requirements
3. Highlight strengths and areas for improvement
4. Provide specific, actionable recommendations
5. Consider industry best practices and trends`,
examples: [
"Resume Analysis: \"This resume shows strong technical skills but could benefit from quantifiable achievements. Consider adding metrics like 'increased efficiency by 25%' or 'managed team of 8 developers'.\"",
'Cover Letter Review: "The cover letter effectively addresses the job requirements but could be more specific about how your experience directly relates to their needs."',
],
outputFormat:
"Provide structured analysis with clear sections: Summary, Strengths, Areas for Improvement, and Recommendations.",
chainOfThought: true,
});
// Financial Domain
this.domainTemplates.set("financial", {
role: "senior financial analyst and investment advisor",
context:
"You are analyzing financial data and providing investment insights and recommendations.",
instructions: `When analyzing financial information:
1. Examine key financial metrics and ratios
2. Identify trends and patterns in the data
3. Assess risk factors and opportunities
4. Provide data-driven insights and recommendations
5. Consider market conditions and economic factors`,
examples: [
'Financial Analysis: "The company shows strong revenue growth of 15% YoY, but operating margins have declined from 12% to 9%, indicating potential cost management issues."',
'Investment Review: "Based on the P/E ratio of 18 and strong cash flow, this appears to be a solid investment opportunity, though market volatility should be considered."',
],
outputFormat:
"Present analysis with clear financial metrics, trends, and actionable recommendations.",
chainOfThought: true,
});
// Content Analysis Domain
this.domainTemplates.set("contentAnalysis", {
role: "content strategist and digital marketing expert",
context:
"You are analyzing content for marketing effectiveness, SEO optimization, and audience engagement.",
instructions: `When analyzing content:
1. Assess readability and engagement potential
2. Identify SEO opportunities and issues
3. Evaluate brand voice and messaging consistency
4. Suggest improvements for audience targeting
5. Consider content performance metrics`,
examples: [
"Content Review: \"The article has good structure but could benefit from more specific keywords. Consider adding 'digital transformation' and 'cloud migration' to improve SEO.\"",
'Engagement Analysis: "The content is informative but lacks emotional hooks. Adding personal stories or case studies could increase engagement."',
],
outputFormat:
"Provide analysis with specific recommendations for content improvement and optimization.",
chainOfThought: false,
});
// Technical Domain
this.domainTemplates.set("technical", {
role: "senior software engineer and technical architect",
context:
"You are analyzing technical documentation and code to provide development insights and recommendations.",
instructions: `When analyzing technical content:
1. Evaluate code quality and best practices
2. Identify potential security vulnerabilities
3. Assess scalability and performance implications
4. Suggest architectural improvements
5. Consider maintainability and documentation`,
examples: [
'Code Review: "The function is well-structured but could benefit from error handling. Consider adding try-catch blocks for database operations."',
'Architecture Analysis: "The microservices approach is good, but consider implementing a service mesh for better communication management."',
],
outputFormat:
"Provide technical analysis with specific recommendations for improvement and optimization.",
chainOfThought: true,
});
}
/**
* Initialize few-shot learning examples
*/
private initializeFewShotExamples(): void {
// General examples
this.fewShotExamples.set("summarize", [
{
input:
"Long technical document about machine learning algorithms, neural networks, deep learning applications, and practical implementation strategies...",
output:
"This document explains machine learning fundamentals, covering supervised learning algorithms, neural networks, and practical applications in data science. Key topics include algorithm selection, model training, and performance optimization techniques.",
},
]);
this.fewShotExamples.set("analyze", [
{
input:
"Financial report showing Q3 revenue of $2.5M, 15% growth, new product launches, customer acquisition data...",
output:
"Analysis shows 15% revenue growth driven by new product launches. Key insights: Q3 performance exceeded expectations, customer acquisition increased 25%, operational efficiency improved 8%. Recommendations: Continue product innovation, optimize customer onboarding process.",
},
]);
// Job application examples
this.fewShotExamples.set("jobApplication_summarize", [
{
input:
"Resume with 5 years software engineering experience, Python/JavaScript skills, team lead experience...",
output:
"Experienced software engineer with 5 years in full-stack development. Strong technical skills in Python and JavaScript, proven leadership experience managing development teams. Key strengths: problem-solving, team collaboration, and technical innovation.",
},
]);
// Financial examples
this.fewShotExamples.set("financial_analyze", [
{
input:
"Company financials: Revenue $10M, Expenses $7M, Net Income $3M, Debt $2M, Cash $5M...",
output:
"Strong financial position with 30% net margin and healthy cash reserves. Revenue growth of 20% YoY indicates good market traction. Debt-to-equity ratio of 0.2 shows conservative leverage. Recommendation: Consider strategic investments for continued growth.",
},
]);
}
/**
* Track prompt performance for future optimization
*/
trackPerformance(promptId: string, performance: PromptPerformance): void {
this.promptHistory.set(promptId, performance);
}
/**
* Get performance insights for prompt optimization
*/
getPerformanceInsights(): Map<string, PromptPerformance> {
return new Map(this.promptHistory);
}
}
/**
* Prompt Builder class for constructing optimized prompts
*/
class PromptBuilder {
private role: string = "";
private context: string = "";
private instructions: string = "";
private examples: any[] = [];
private chainOfThought: boolean = false;
private outputFormat: string = "";
private dataContext: string = "";
addRole(role: string): PromptBuilder {
this.role = `You are an ${role}.`;
return this;
}
addContext(context: string): PromptBuilder {
this.context = `Context:\n${context}`;
return this;
}
addInstructions(instructions: string): PromptBuilder {
this.instructions = `Instructions:\n${instructions}`;
return this;
}
addExamples(examples: any[]): PromptBuilder {
if (examples.length > 0) {
this.examples = examples;
}
return this;
}
addChainOfThought(): PromptBuilder {
this.chainOfThought = true;
return this;
}
addOutputFormat(outputFormat: string): PromptBuilder {
this.outputFormat = `Output Format:\n${outputFormat}`;
return this;
}
addDataContext(dataContext: string): PromptBuilder {
this.dataContext = dataContext;
return this;
}
build(): string {
const parts = [this.role];
if (this.context) parts.push(this.context);
if (this.instructions) parts.push(this.instructions);
if (this.chainOfThought) {
parts.push(`Please think through this step by step:
1. First, analyze the input data and identify key elements
2. Apply your expertise to process the information
3. Generate insights and conclusions
4. Format the output according to the requirements`);
}
if (this.examples.length > 0) {
parts.push("Examples:");
this.examples.forEach((example, index) => {
parts.push(`Example ${index + 1}:`);
parts.push(`Input: ${example.input}`);
parts.push(`Output: ${example.output}`);
});
}
if (this.outputFormat) parts.push(this.outputFormat);
if (this.dataContext) parts.push(this.dataContext);
return parts.join("\n\n");
}
}
// Export singleton instance
export const promptOptimizer = new PromptOptimizer();
+164 -1
View File
@@ -667,11 +667,45 @@ const processLLMNode = async (
nodeLabelToId?: Map<string, string>
) => {
const config = node.data.config;
const prompt = config.prompt || "Process the following input: {{input}}";
let prompt = config.prompt || "Process the following input: {{input}}";
const model = config.model || "gpt-3.5-turbo";
const temperature = config.temperature || 0.7;
const maxTokens = config.maxTokens || 1000;
// Check if we should optimize the prompt
if (config.optimizePrompt !== false) {
try {
// Import the prompt optimizer
const { promptOptimizer } = require("../services/promptOptimizer");
// Create node context for optimization
const nodeContext = {
dataType: determineNodeDataType(node, nodeOutputs),
previousNodes: getPreviousNodeIds(node, nodeOutputs),
intent: "AI_ANALYSIS",
domain: determineNodeDomain(node, nodeOutputs),
workflowType: "ai_analysis",
availableData: nodeOutputs,
};
// Generate optimized prompt
const optimizedPrompt = promptOptimizer.generateOptimizedPrompt(
prompt,
extractEntitiesFromPrompt(prompt),
nodeContext,
nodeOutputs
);
// Use optimized prompt if it's different and better
if (optimizedPrompt && optimizedPrompt !== prompt) {
console.log("Using optimized prompt for LLM node:", node.id);
prompt = optimizedPrompt;
}
} catch (error) {
console.warn("Failed to optimize prompt, using original:", error);
}
}
// Apply variable substitution to the prompt
const processedPrompt = substituteVariables(
prompt,
@@ -990,3 +1024,132 @@ const processStructuredOutputNode = async (
return { output: mockStructuredOutput, model, schema };
};
// Helper functions for prompt optimization
function determineNodeDataType(
node: WorkflowNode,
nodeOutputs: Map<string, NodeOutput>
): string {
// Check if this is a data input node
if (node.data.type === "dataInput") {
return node.data.config?.dataType || "text";
}
// Check previous nodes for data type
const previousOutput = Array.from(nodeOutputs.values()).pop();
if (previousOutput?.data?.type) {
return previousOutput.data.type;
}
// Check if previous output looks like specific data types
if (previousOutput?.output) {
const output = previousOutput.output;
if (typeof output === "string") {
if (output.startsWith("http")) return "url";
if (output.includes("{") && output.includes("}")) return "json";
if (output.includes(",") && output.includes("\n")) return "csv";
}
}
return "text";
}
function getPreviousNodeIds(
node: WorkflowNode,
nodeOutputs: Map<string, NodeOutput>
): string[] {
return Array.from(nodeOutputs.keys());
}
function determineNodeDomain(
node: WorkflowNode,
nodeOutputs: Map<string, NodeOutput>
): string {
// Check node label for domain indicators
const label = node.data.label?.toLowerCase() || "";
if (
label.includes("resume") ||
label.includes("cv") ||
label.includes("job")
) {
return "jobApplication";
}
if (
label.includes("financial") ||
label.includes("revenue") ||
label.includes("profit")
) {
return "financial";
}
if (label.includes("legal") || label.includes("contract")) {
return "legal";
}
if (label.includes("medical") || label.includes("health")) {
return "medical";
}
if (label.includes("technical") || label.includes("code")) {
return "technical";
}
if (label.includes("content") || label.includes("marketing")) {
return "contentAnalysis";
}
// Check previous outputs for domain indicators
for (const output of nodeOutputs.values()) {
if (output.output && typeof output.output === "string") {
const text = output.output.toLowerCase();
if (text.includes("resume") || text.includes("cv"))
return "jobApplication";
if (text.includes("financial") || text.includes("revenue"))
return "financial";
if (text.includes("legal") || text.includes("contract")) return "legal";
if (text.includes("medical") || text.includes("health")) return "medical";
if (text.includes("technical") || text.includes("code"))
return "technical";
if (text.includes("content") || text.includes("marketing"))
return "contentAnalysis";
}
}
return "general";
}
function extractEntitiesFromPrompt(prompt: string): any {
// Simple entity extraction from prompt text
const entities: any = {
aiTasks: [],
dataTypes: [],
};
const lowerPrompt = prompt.toLowerCase();
// Extract AI tasks
if (lowerPrompt.includes("summarize")) entities.aiTasks.push("summarize");
if (lowerPrompt.includes("analyze")) entities.aiTasks.push("analyze");
if (lowerPrompt.includes("extract")) entities.aiTasks.push("extract");
if (lowerPrompt.includes("classify")) entities.aiTasks.push("classify");
if (lowerPrompt.includes("generate")) entities.aiTasks.push("generate");
if (lowerPrompt.includes("translate")) entities.aiTasks.push("translate");
if (lowerPrompt.includes("sentiment")) entities.aiTasks.push("sentiment");
if (lowerPrompt.includes("compare")) entities.aiTasks.push("compare");
// Extract data types
if (lowerPrompt.includes("resume") || lowerPrompt.includes("cv"))
entities.dataTypes.push("resume");
if (lowerPrompt.includes("pdf")) entities.dataTypes.push("pdf");
if (lowerPrompt.includes("json")) entities.dataTypes.push("json");
if (lowerPrompt.includes("csv")) entities.dataTypes.push("csv");
if (lowerPrompt.includes("url")) entities.dataTypes.push("url");
if (lowerPrompt.includes("financial")) entities.dataTypes.push("financial");
if (lowerPrompt.includes("legal")) entities.dataTypes.push("legal");
if (lowerPrompt.includes("medical")) entities.dataTypes.push("medical");
if (lowerPrompt.includes("technical")) entities.dataTypes.push("technical");
return entities;
}
+22 -30
View File
@@ -539,39 +539,31 @@ function generateDefaultValue(entities: any): string {
}
/**
* Generate AI prompt based on entities
* Generate AI prompt based on entities using the new prompt optimizer
*/
function generateAIPrompt(entities: any): string {
const tasks = entities.aiTasks || [];
const dataTypes = entities.dataTypes || [];
function generateAIPrompt(
entities: any,
userInput?: string,
nodeContext?: any
): string {
// Import the prompt optimizer
const { promptOptimizer } = require("../services/promptOptimizer");
// Special handling for PDF files
if (dataTypes.includes("pdf")) {
if (tasks.includes("summarize")) {
return "Summarize the PDF document in 2-3 sentences: {{input.output}}";
}
if (tasks.includes("analyze")) {
return "Analyze the PDF content and provide insights: {{input.output}}";
}
if (tasks.includes("extract")) {
return "Extract key information from the PDF: {{input.output}}";
}
return "Process the PDF content: {{input.output}}";
}
// Create node context if not provided
const context = nodeContext || {
dataType: determineInputDataType(entities),
previousNodes: [],
intent: "AI_ANALYSIS",
availableData: new Map(),
};
if (tasks.includes("summarize")) {
return "Summarize the following content in 2-3 sentences: {{input.output}}";
}
if (tasks.includes("analyze")) {
return "Analyze the following content and provide insights: {{input.output}}";
}
if (tasks.includes("classify")) {
return "Classify the following content into categories: {{input.output}}";
}
return "Process the following content: {{input.output}}";
// Generate optimized prompt
return promptOptimizer.generateOptimizedPrompt(
userInput || "Process the input data",
entities,
context,
context.availableData
);
}
/**