Spaces:
Running
Running
""" | |
Inventory management tools for the FoodWise agent. | |
These tools provide the core functionality for interacting with the Notion-based | |
food inventory database through the LangGraph agent. | |
""" | |
from typing import List, Dict, Any, Optional, Union | |
from datetime import datetime, date, timedelta | |
from pydantic import BaseModel, Field | |
from langchain_core.tools import tool | |
from ..notion.notion_client import FoodWiseNotionClient | |
class InventoryItem(BaseModel): | |
"""Model for inventory items following the Notion database schema.""" | |
name: str = Field(description="Name of the food item") | |
category: str = Field(description="Food category (Dairy, Raw Meat, Vegetables, etc.)") | |
storage_type: str = Field(description="Storage type (Pantry, Refrigerator, Freezer)") | |
quantity: float = Field(description="Quantity of the item") | |
unit: str = Field(description="Unit of measurement (lbs, oz, pieces, etc.)") | |
best_by_date: Optional[str] = Field(default=None, description="Best by/expiration date (YYYY-MM-DD)") | |
purchase_date: Optional[str] = Field(default=None, description="Purchase date (YYYY-MM-DD)") | |
opened_date: Optional[str] = Field(default=None, description="Date opened (YYYY-MM-DD)") | |
location_shelf: Optional[str] = Field(default=None, description="Specific storage location/shelf") | |
fridge_zone: Optional[str] = Field(default=None, description="Fridge zone for refrigerated items") | |
tags: Optional[List[str]] = Field(default=None, description="Tags (Low Stock, Organic, etc.)") | |
temperature_sensitive: bool = Field(default=False, description="Requires temperature control") | |
cooked_raw_status: str = Field(default="Raw", description="Cooking status (Raw, Cooked, Partially Cooked)") | |
prep_notes: Optional[str] = Field(default=None, description="Preparation notes") | |
def get_inventory( | |
filter_type: Optional[str] = None, | |
category: Optional[str] = None, | |
storage_type: Optional[str] = None, | |
expiring_days: Optional[int] = None | |
) -> List[Dict[str, Any]]: | |
""" | |
Retrieve inventory items with optional filtering. | |
Args: | |
filter_type: Filter by type ("expiring_soon", "low_stock", "all") | |
category: Filter by specific category | |
storage_type: Filter by storage type (Pantry, Refrigerator, Freezer) | |
expiring_days: Show items expiring within this many days | |
Returns: | |
List of inventory items matching the criteria | |
""" | |
try: | |
notion_client = FoodWiseNotionClient() | |
# Handle different filter types | |
if filter_type == "expiring_soon" or expiring_days: | |
days = expiring_days or 7 | |
return notion_client.get_expiring_items(days) | |
# Build filter conditions | |
filter_conditions = None | |
if category or storage_type: | |
conditions = [] | |
if category: | |
conditions.append({ | |
"property": "Category", | |
"select": {"equals": category} | |
}) | |
if storage_type: | |
conditions.append({ | |
"property": "Storage Type", | |
"select": {"equals": storage_type} | |
}) | |
if len(conditions) == 1: | |
filter_conditions = conditions[0] | |
else: | |
filter_conditions = {"and": conditions} | |
return notion_client.query_inventory(filter_conditions=filter_conditions) | |
except Exception as e: | |
# Fallback to sample data if Notion fails | |
return [{"error": f"Failed to connect to Notion: {e}"}] | |
def add_item( | |
name: str, | |
category: str, | |
storage_type: str, | |
quantity: float, | |
unit: str, | |
best_by_date: Optional[str] = None, | |
purchase_date: Optional[str] = None, | |
location_shelf: Optional[str] = None, | |
fridge_zone: Optional[str] = None, | |
tags: Optional[List[str]] = None, | |
temperature_sensitive: bool = False, | |
cooked_raw_status: str = "Raw", | |
prep_notes: Optional[str] = None | |
) -> Dict[str, Any]: | |
""" | |
Add a new food item to the inventory. | |
Args: | |
name: Name of the food item | |
category: Food category (must match schema options) | |
storage_type: Storage type (Pantry, Refrigerator, Freezer) | |
quantity: Quantity of the item | |
unit: Unit of measurement | |
best_by_date: Best by date (YYYY-MM-DD format) | |
purchase_date: Purchase date (YYYY-MM-DD format) | |
location_shelf: Specific storage location | |
fridge_zone: Fridge zone for refrigerated items | |
tags: List of tags | |
temperature_sensitive: Whether item requires temperature control | |
cooked_raw_status: Cooking status | |
prep_notes: Preparation notes | |
Returns: | |
Success status and item details | |
""" | |
# Validate required fields | |
valid_categories = [ | |
"Dairy", "Raw Meat", "Cooked Meat", "Vegetables", "Fruits", | |
"Canned Goods", "Grains", "Pasta", "Spices", "Oils", | |
"Baking Supplies", "Snacks", "Condiments", "Leftovers", | |
"Beverages", "Prepared Meals", "Ice Cream" | |
] | |
if category not in valid_categories: | |
return {"success": False, "error": f"Invalid category. Must be one of: {valid_categories}"} | |
valid_storage_types = ["Pantry", "Refrigerator", "Freezer"] | |
if storage_type not in valid_storage_types: | |
return {"success": False, "error": f"Invalid storage type. Must be one of: {valid_storage_types}"} | |
try: | |
notion_client = FoodWiseNotionClient() | |
# Prepare item data | |
item_data = { | |
"name": name, | |
"category": category, | |
"storage_type": storage_type, | |
"quantity": quantity, | |
"unit": unit, | |
"best_by_date": best_by_date, | |
"purchase_date": purchase_date, | |
"location_shelf": location_shelf, | |
"fridge_zone": fridge_zone, | |
"tags": tags, | |
"temperature_sensitive": temperature_sensitive, | |
"cooked_raw_status": cooked_raw_status, | |
"prep_notes": prep_notes | |
} | |
# Add to Notion database | |
created_item = notion_client.add_inventory_item(item_data) | |
return { | |
"success": True, | |
"message": f"Successfully added {quantity} {unit} of {name} to {storage_type}", | |
"item": created_item | |
} | |
except Exception as e: | |
return { | |
"success": False, | |
"error": f"Failed to add item to Notion: {e}" | |
} | |
def query_item( | |
search_term: str, | |
search_type: str = "name" | |
) -> List[Dict[str, Any]]: | |
""" | |
Search for specific items in the inventory. | |
Args: | |
search_term: Term to search for | |
search_type: Type of search ("name", "category", "tag") | |
Returns: | |
List of items matching the search criteria | |
""" | |
try: | |
notion_client = FoodWiseNotionClient() | |
if search_type == "name": | |
return notion_client.search_items(search_term) | |
elif search_type == "category": | |
return notion_client.query_inventory(filter_conditions={ | |
"property": "Category", | |
"select": {"equals": search_term} | |
}) | |
else: | |
# Fallback to name search | |
return notion_client.search_items(search_term) | |
except Exception as e: | |
return [{"error": f"Failed to search Notion: {e}"}] | |
class UpdateItemInput(BaseModel): | |
page_id: str = Field(description="Notion page ID of the item to update") | |
updated_data: Dict[str, Any] = Field(description="Dictionary of fields to update") | |
def update_item(page_id: str, updated_data: Dict[str, Any]) -> Dict[str, Any]: | |
"""Update an existing inventory item.""" | |
try: | |
notion_client = FoodWiseNotionClient() | |
updated_item = notion_client.update_inventory_item(page_id, updated_data) | |
return { | |
"success": True, | |
"message": f"Item {page_id} updated successfully", | |
"item": updated_item | |
} | |
except Exception as e: | |
return {"success": False, "error": f"Failed to update item: {str(e)}"} | |
class RemoveItemInput(BaseModel): | |
page_id: str = Field(description="Notion page ID of the item to remove") | |
def remove_item(page_id: str) -> Dict[str, Any]: | |
"""Remove an inventory item.""" | |
try: | |
notion_client = FoodWiseNotionClient() | |
result = notion_client.remove_inventory_item(page_id) | |
return result | |
except Exception as e: | |
return {"success": False, "error": f"Failed to remove item: {str(e)}"} | |
def get_inventory_tools() -> List: | |
""" | |
Get all available inventory management tools. | |
Returns: | |
List of LangChain tools for the agent | |
""" | |
return [ | |
get_inventory, | |
add_item, | |
query_item, | |
update_item, | |
remove_item | |
] | |