Sample Applications
Here are some example applications built with the Pocket Flow Framework to demonstrate its capabilities.
1. Document Processing Pipeline
A flow that processes documents through multiple stages:
import { BaseNode, Flow, DEFAULT_ACTION } from "../src/pocket";
class DocumentLoaderNode extends BaseNode {
async prep(sharedState: any) {
return sharedState.documentPath;
}
async execCore(path: string) {
// Simulate loading document
return { content: "Sample document content" };
}
async post(prepResult: any, execResult: any, sharedState: any) {
sharedState.document = execResult;
return DEFAULT_ACTION;
}
}
class TextExtractorNode extends BaseNode {
async prep(sharedState: any) {
return sharedState.document;
}
async execCore(document: any) {
return document.content.toLowerCase();
}
async post(prepResult: any, execResult: any, sharedState: any) {
sharedState.extractedText = execResult;
return DEFAULT_ACTION;
}
}
// Create and connect nodes
const loader = new DocumentLoaderNode();
const extractor = new TextExtractorNode();
loader.addSuccessor(extractor);
// Create flow
const docFlow = new Flow(loader);
// Run the flow
await docFlow.run({
documentPath: "path/to/document.pdf"
});
2. Data Processing with Retry Logic
An example showing retry capabilities for API calls:
class ApiNode extends RetryNode {
constructor() {
super(3, 1000); // 3 retries, 1 second interval
}
async prep(sharedState: any) {
return sharedState.apiEndpoint;
}
async execCore(endpoint: string) {
// Simulate API call that might fail
const response = await fetch(endpoint);
if (!response.ok) throw new Error("API call failed");
return response.json();
}
async post(prepResult: any, execResult: any, sharedState: any) {
sharedState.apiResponse = execResult;
return DEFAULT_ACTION;
}
}
3. Parallel Processing with BatchFlow
Example of processing multiple items in parallel:
class ImageProcessingFlow extends BatchFlow {
async prep(sharedState: any) {
// Return array of image paths to process
return sharedState.imagePaths;
}
async post(prepResults: string[], results: any[], sharedState: any) {
sharedState.processedImages = results;
return DEFAULT_ACTION;
}
}
// Usage
const batchFlow = new ImageProcessingFlow(processingNode);
await batchFlow.run({
imagePaths: [
"image1.jpg",
"image2.jpg",
"image3.jpg"
]
});
4. Conditional Branching Flow
Example of a flow with different paths based on conditions:
class ValidationNode extends BaseNode {
async prep(sharedState: any) {
return sharedState.data;
}
async execCore(data: any) {
return data.isValid;
}
async post(prepResult: any, execResult: any, sharedState: any) {
return execResult ? "valid" : "invalid";
}
}
// Create nodes
const validator = new ValidationNode();
const successHandler = new SuccessNode();
const errorHandler = new ErrorNode();
// Set up branching
validator.addSuccessor(successHandler, "valid");
validator.addSuccessor(errorHandler, "invalid");
// Create and run flow
const flow = new Flow(validator);
await flow.run({
data: { isValid: true }
});
5. Nested Flows Example
Demonstrating how to compose complex workflows:
// Sub-flow for data preprocessing
const preprocessFlow = new Flow(preprocessNode);
preprocessFlow.addSuccessor(validationNode);
// Sub-flow for model inference
const inferenceFlow = new Flow(modelNode);
inferenceFlow.addSuccessor(postprocessNode);
// Main flow combining sub-flows
preprocessFlow.addSuccessor(inferenceFlow);
const mainFlow = new Flow(preprocessFlow);
// Run the composed flow
await mainFlow.run({
input: "Raw data"
});
These examples demonstrate key features of the framework: - Basic node implementation - Retry logic for robust operations - Parallel processing with BatchFlow - Conditional branching - Flow composition
Each example can be extended and customized based on specific requirements.