feat: add new examples from pocketflow-academy

This commit is contained in:
Alan ALves
2025-03-19 10:31:04 -03:00
parent 84720ceebd
commit 557a14f695
129 changed files with 13455 additions and 0 deletions
@@ -0,0 +1,64 @@
# PocketFlow Nested BatchFlow Example
This example demonstrates Nested BatchFlow using a simple school grades calculator.
## What this Example Does
Calculates average grades for:
1. Each student in a class
2. Each class in the school
## Structure
```
school/
├── class_a/
│ ├── student1.txt (grades: 7.5, 8.0, 9.0)
│ └── student2.txt (grades: 8.5, 7.0, 9.5)
└── class_b/
├── student3.txt (grades: 6.5, 8.5, 7.0)
└── student4.txt (grades: 9.0, 9.5, 8.0)
```
## How it Works
1. **Outer BatchFlow (SchoolBatchFlow)**
- Processes each class folder
- Returns parameters like: `{"class": "class_a"}`
2. **Inner BatchFlow (ClassBatchFlow)**
- Processes each student file in a class
- Returns parameters like: `{"student": "student1.txt"}`
3. **Base Flow**
- Loads student grades
- Calculates average
- Saves result
## Running the Example
```bash
pip install -r requirements.txt
python main.py
```
## Expected Output
```
Processing class_a...
- student1: Average = 8.2
- student2: Average = 8.3
Class A Average: 8.25
Processing class_b...
- student3: Average = 7.3
- student4: Average = 8.8
Class B Average: 8.05
School Average: 8.15
```
## Key Concepts
1. **Nested BatchFlow**: One BatchFlow inside another
2. **Parameter Inheritance**: Inner flow gets parameters from outer flow
3. **Hierarchical Processing**: Process data in a tree-like structure
+73
View File
@@ -0,0 +1,73 @@
import os
from pocketflow import Flow, BatchFlow
from nodes import LoadGrades, CalculateAverage
def create_base_flow():
"""Create base flow for processing one student's grades."""
# Create nodes
load = LoadGrades()
calc = CalculateAverage()
# Connect nodes
load - "calculate" >> calc
# Create and return flow
return Flow(start=load)
class ClassBatchFlow(BatchFlow):
"""BatchFlow for processing all students in a class."""
def prep(self, shared):
"""Generate parameters for each student in the class."""
# Get class folder from parameters
class_folder = self.params["class"]
# List all student files
class_path = os.path.join("school", class_folder)
students = [f for f in os.listdir(class_path) if f.endswith(".txt")]
# Return parameters for each student
return [{"student": student} for student in students]
def post(self, shared, prep_res, exec_res):
"""Calculate and print class average."""
class_name = self.params["class"]
class_results = shared["results"][class_name]
class_average = sum(class_results.values()) / len(class_results)
print(f"Class {class_name.split('_')[1].upper()} Average: {class_average:.2f}\n")
return "default"
class SchoolBatchFlow(BatchFlow):
"""BatchFlow for processing all classes in the school."""
def prep(self, shared):
"""Generate parameters for each class."""
# List all class folders
classes = [d for d in os.listdir("school") if os.path.isdir(os.path.join("school", d))]
# Return parameters for each class
return [{"class": class_name} for class_name in classes]
def post(self, shared, prep_res, exec_res):
"""Calculate and print school average."""
all_grades = []
for class_results in shared["results"].values():
all_grades.extend(class_results.values())
school_average = sum(all_grades) / len(all_grades)
print(f"School Average: {school_average:.2f}")
return "default"
def create_flow():
"""Create the complete nested batch processing flow."""
# Create base flow for single student
base_flow = create_base_flow()
# Wrap in ClassBatchFlow for processing all students in a class
class_flow = ClassBatchFlow(start=base_flow)
# Wrap in SchoolBatchFlow for processing all classes
school_flow = SchoolBatchFlow(start=class_flow)
return school_flow
+42
View File
@@ -0,0 +1,42 @@
import os
from flow import create_flow
def create_sample_data():
"""Create sample grade files."""
# Create directory structure
os.makedirs("school/class_a", exist_ok=True)
os.makedirs("school/class_b", exist_ok=True)
# Sample grades
data = {
"class_a": {
"student1.txt": [7.5, 8.0, 9.0],
"student2.txt": [8.5, 7.0, 9.5]
},
"class_b": {
"student3.txt": [6.5, 8.5, 7.0],
"student4.txt": [9.0, 9.5, 8.0]
}
}
# Create files
for class_name, students in data.items():
for student, grades in students.items():
file_path = os.path.join("school", class_name, student)
with open(file_path, 'w') as f:
for grade in grades:
f.write(f"{grade}\n")
def main():
"""Run the nested batch example."""
# Create sample data
create_sample_data()
print("Processing school grades...\n")
# Create and run flow
flow = create_flow()
flow.run({})
if __name__ == "__main__":
main()
+52
View File
@@ -0,0 +1,52 @@
import os
from pocketflow import Node
class LoadGrades(Node):
"""Node that loads grades from a student's file."""
def prep(self, shared):
"""Get file path from parameters."""
class_name = self.params["class"]
student_file = self.params["student"]
return os.path.join("school", class_name, student_file)
def exec(self, file_path):
"""Load and parse grades from file."""
with open(file_path, 'r') as f:
# Each line is a grade
grades = [float(line.strip()) for line in f]
return grades
def post(self, shared, prep_res, grades):
"""Store grades in shared store."""
shared["grades"] = grades
return "calculate"
class CalculateAverage(Node):
"""Node that calculates average grade."""
def prep(self, shared):
"""Get grades from shared store."""
return shared["grades"]
def exec(self, grades):
"""Calculate average."""
return sum(grades) / len(grades)
def post(self, shared, prep_res, average):
"""Store and print result."""
# Store in results dictionary
if "results" not in shared:
shared["results"] = {}
class_name = self.params["class"]
student = self.params["student"]
if class_name not in shared["results"]:
shared["results"][class_name] = {}
shared["results"][class_name][student] = average
# Print individual result
print(f"- {student}: Average = {average:.1f}")
return "default"
@@ -0,0 +1 @@
pocketflow
@@ -0,0 +1,3 @@
7.5
8.0
9.0
@@ -0,0 +1,3 @@
8.5
7.0
9.5
@@ -0,0 +1,3 @@
6.5
8.5
7.0
@@ -0,0 +1,3 @@
9.0
9.5
8.0