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
+90
View File
@@ -0,0 +1,90 @@
# PocketFlow Async Basic Example
This example demonstrates async operations using a simple Recipe Finder that:
1. Fetches recipes from an API (async HTTP)
2. Processes them with an LLM (async LLM)
3. Waits for user confirmation (async input)
## What this Example Does
When you run the example:
1. You enter an ingredient (e.g., "chicken")
2. It searches for recipes (async API call)
3. It suggests a recipe (async LLM call)
4. You approve or reject the suggestion
5. If rejected, it tries again with a different recipe
## How it Works
1. **FetchRecipes (AsyncNode)**
```python
async def prep_async(self, shared):
ingredient = input("Enter ingredient: ")
return ingredient
async def exec_async(self, ingredient):
# Async API call
recipes = await fetch_recipes(ingredient)
return recipes
```
2. **SuggestRecipe (AsyncNode)**
```python
async def exec_async(self, recipes):
# Async LLM call
suggestion = await call_llm_async(
f"Choose best recipe from: {recipes}"
)
return suggestion
```
3. **GetApproval (AsyncNode)**
```python
async def post_async(self, shared, prep_res, suggestion):
# Async user input
answer = await get_user_input(
f"Accept {suggestion}? (y/n): "
)
return "accept" if answer == "y" else "retry"
```
## Running the Example
```bash
pip install -r requirements.txt
python main.py
```
## Sample Interaction
```
Enter ingredient: chicken
Fetching recipes...
Found 3 recipes.
Suggesting best recipe...
How about: Grilled Chicken with Herbs
Accept this recipe? (y/n): n
Suggesting another recipe...
How about: Chicken Stir Fry
Accept this recipe? (y/n): y
Great choice! Here's your recipe...
```
## Key Concepts
1. **Async Operations**: Using `async/await` for:
- API calls (non-blocking I/O)
- LLM calls (potentially slow)
- User input (waiting for response)
2. **AsyncNode Methods**:
- `prep_async`: Setup and data gathering
- `exec_async`: Main async processing
- `post_async`: Post-processing and decisions
3. **Flow Control**:
- Actions ("accept"/"retry") control flow
- Retry loop for rejected suggestions
+27
View File
@@ -0,0 +1,27 @@
"""AsyncFlow implementation for recipe finder."""
from pocketflow import AsyncFlow, Node
from nodes import FetchRecipes, SuggestRecipe, GetApproval
class NoOp(Node):
"""Node that does nothing, used to properly end the flow."""
pass
def create_flow():
"""Create and connect nodes into a flow."""
# Create nodes
fetch = FetchRecipes()
suggest = SuggestRecipe()
approve = GetApproval()
end = NoOp()
# Connect nodes
fetch - "suggest" >> suggest
suggest - "approve" >> approve
approve - "retry" >> suggest # Loop back for another suggestion
approve - "accept" >> end # Properly end the flow
# Create flow starting with fetch
flow = AsyncFlow(start=fetch)
return flow
+20
View File
@@ -0,0 +1,20 @@
import asyncio
from flow import create_flow
async def main():
"""Run the recipe finder flow."""
# Create flow
flow = create_flow()
# Create shared store
shared = {}
# Run flow
print("\nWelcome to Recipe Finder!")
print("------------------------")
await flow.run_async(shared)
print("\nThanks for using Recipe Finder!")
if __name__ == "__main__":
# Run the async main function
asyncio.run(main())
+63
View File
@@ -0,0 +1,63 @@
from pocketflow import AsyncNode
from utils import fetch_recipes, call_llm_async, get_user_input
class FetchRecipes(AsyncNode):
"""AsyncNode that fetches recipes."""
async def prep_async(self, shared):
"""Get ingredient from user."""
ingredient = await get_user_input("Enter ingredient: ")
return ingredient
async def exec_async(self, ingredient):
"""Fetch recipes asynchronously."""
recipes = await fetch_recipes(ingredient)
return recipes
async def post_async(self, shared, prep_res, recipes):
"""Store recipes and continue."""
shared["recipes"] = recipes
shared["ingredient"] = prep_res
return "suggest"
class SuggestRecipe(AsyncNode):
"""AsyncNode that suggests a recipe using LLM."""
async def prep_async(self, shared):
"""Get recipes from shared store."""
return shared["recipes"]
async def exec_async(self, recipes):
"""Get suggestion from LLM."""
suggestion = await call_llm_async(
f"Choose best recipe from: {', '.join(recipes)}"
)
return suggestion
async def post_async(self, shared, prep_res, suggestion):
"""Store suggestion and continue."""
shared["suggestion"] = suggestion
return "approve"
class GetApproval(AsyncNode):
"""AsyncNode that gets user approval."""
async def prep_async(self, shared):
"""Get current suggestion."""
return shared["suggestion"]
async def exec_async(self, suggestion):
"""Ask for user approval."""
answer = await get_user_input(f"\nAccept this recipe? (y/n): ")
return answer
async def post_async(self, shared, prep_res, answer):
"""Handle user's decision."""
if answer == "y":
print("\nGreat choice! Here's your recipe...")
print(f"Recipe: {shared['suggestion']}")
print(f"Ingredient: {shared['ingredient']}")
return "accept"
else:
print("\nLet's try another recipe...")
return "retry"
@@ -0,0 +1,3 @@
pocketflow
aiohttp>=3.8.0 # For async HTTP requests
openai>=1.0.0 # For async LLM calls
+45
View File
@@ -0,0 +1,45 @@
import asyncio
import aiohttp
from openai import AsyncOpenAI
async def fetch_recipes(ingredient):
"""Fetch recipes from an API asynchronously."""
print(f"Fetching recipes for {ingredient}...")
# Simulate API call with delay
await asyncio.sleep(1)
# Mock recipes (in real app, would fetch from API)
recipes = [
f"{ingredient} Stir Fry",
f"Grilled {ingredient} with Herbs",
f"Baked {ingredient} with Vegetables"
]
print(f"Found {len(recipes)} recipes.")
return recipes
async def call_llm_async(prompt):
"""Make async LLM call."""
print("\nSuggesting best recipe...")
# Simulate LLM call with delay
await asyncio.sleep(1)
# Mock LLM response (in real app, would call OpenAI)
recipes = prompt.split(": ")[1].split(", ")
suggestion = recipes[1] # Always suggest second recipe
print(f"How about: {suggestion}")
return suggestion
async def get_user_input(prompt):
"""Get user input asynchronously."""
# Create event loop to handle async input
loop = asyncio.get_event_loop()
# Get input in a non-blocking way
answer = await loop.run_in_executor(None, input, prompt)
return answer.lower()