Skip to content

Commit 48809ac

Browse files
authored
Community contribution - cooking assistant (#375)
2 parents 285d9bb + 7921e14 commit 48809ac

File tree

2 files changed

+176
-0
lines changed

2 files changed

+176
-0
lines changed
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# Personal Dietician
2+
3+
This code example searches for recipes on the internet based on the ingredients you have, refines the content based on a dieterary restriction and generates shopping lists.
4+
5+
## How to use
6+
7+
1. Set up the OPENAI api key in the .env file
8+
9+
```bash
10+
OPENAI_API_KEY = 'xxx'
11+
```
12+
13+
2. Copy the python script to the owl/examples folder.
14+
15+
3. Run the script
16+
17+
```bash
18+
python run_gpt4o.py
19+
```
20+
21+
4. You can find the entire thought process of the agent within the log file.
22+
23+
5. Demo Link - https://drive.google.com/drive/folders/10LnMEMf_xQGojHyTAS57vI7oOmjvuKPE?usp=sharing
Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
import os
2+
import logging
3+
import json
4+
5+
from dotenv import load_dotenv
6+
from camel.models import ModelFactory
7+
from camel.types import ModelPlatformType
8+
9+
from camel.toolkits import (
10+
SearchToolkit,
11+
BrowserToolkit,
12+
)
13+
from camel.societies import RolePlaying
14+
from camel.logger import set_log_level, get_logger
15+
16+
17+
from owl.utils import run_society
18+
import pathlib
19+
20+
base_dir = pathlib.Path(__file__).parent.parent
21+
env_path = base_dir / "owl" / ".env"
22+
load_dotenv(dotenv_path=str(env_path))
23+
24+
set_log_level(level="DEBUG")
25+
logger = get_logger(__name__)
26+
file_handler = logging.FileHandler("cooking_companion.log")
27+
file_handler.setLevel(logging.DEBUG)
28+
formatter = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s")
29+
file_handler.setFormatter(formatter)
30+
logger.addHandler(file_handler)
31+
32+
root_logger = logging.getLogger()
33+
root_logger.addHandler(file_handler)
34+
35+
36+
def construct_cooking_society(task: str) -> RolePlaying:
37+
"""Construct a society of agents for the cooking companion.
38+
39+
Args:
40+
task (str): The cooking-related task to be addressed.
41+
42+
Returns:
43+
RolePlaying: A configured society of agents for the cooking companion.
44+
"""
45+
models = {
46+
"user": ModelFactory.create(
47+
model_platform=ModelPlatformType.OPENAI_COMPATIBLE_MODEL,
48+
model_type="gpt-4o",
49+
api_key=os.getenv("OPENAI_API_KEY"),
50+
model_config_dict={"temperature": 0.4},
51+
),
52+
"assistant": ModelFactory.create(
53+
model_platform=ModelPlatformType.OPENAI_COMPATIBLE_MODEL,
54+
model_type="gpt-4o",
55+
api_key=os.getenv("OPENAI_API_KEY"),
56+
model_config_dict={"temperature": 0.4},
57+
),
58+
"recipe_analyst": ModelFactory.create(
59+
model_platform=ModelPlatformType.OPENAI_COMPATIBLE_MODEL,
60+
model_type="gpt-4o",
61+
api_key=os.getenv("OPENAI_API_KEY"),
62+
model_config_dict={"temperature": 0.2},
63+
),
64+
"planning": ModelFactory.create(
65+
model_platform=ModelPlatformType.OPENAI_COMPATIBLE_MODEL,
66+
model_type="gpt-4o",
67+
api_key=os.getenv("OPENAI_API_KEY"),
68+
model_config_dict={"temperature": 0.3},
69+
),
70+
}
71+
72+
browser_toolkit = BrowserToolkit(
73+
headless=False,
74+
web_agent_model=models["recipe_analyst"],
75+
planning_agent_model=models["planning"],
76+
)
77+
78+
tools = [
79+
*browser_toolkit.get_tools(),
80+
SearchToolkit().search_duckduckgo,
81+
]
82+
83+
user_agent_kwargs = {"model": models["user"]}
84+
assistant_agent_kwargs = {"model": models["assistant"], "tools": tools}
85+
86+
task_kwargs = {
87+
"task_prompt": task,
88+
"with_task_specify": False,
89+
}
90+
91+
society = RolePlaying(
92+
**task_kwargs,
93+
user_role_name="user",
94+
user_agent_kwargs=user_agent_kwargs,
95+
assistant_role_name="cooking_assistant",
96+
assistant_agent_kwargs=assistant_agent_kwargs,
97+
)
98+
99+
return society
100+
101+
102+
def analyze_chat_history(chat_history):
103+
"""Analyze chat history and extract tool call information."""
104+
print("\n============ Tool Call Analysis ============")
105+
logger.info("========== Starting tool call analysis ==========")
106+
107+
tool_calls = []
108+
for i, message in enumerate(chat_history):
109+
if message.get("role") == "assistant" and "tool_calls" in message:
110+
for tool_call in message.get("tool_calls", []):
111+
if tool_call.get("type") == "function":
112+
function = tool_call.get("function", {})
113+
tool_info = {
114+
"call_id": tool_call.get("id"),
115+
"name": function.get("name"),
116+
"arguments": function.get("arguments"),
117+
"message_index": i,
118+
}
119+
tool_calls.append(tool_info)
120+
print(f"Tool Call: {function.get('name')} Args: {function.get('arguments')}")
121+
logger.info(f"Tool Call: {function.get('name')} Args: {function.get('arguments')}")
122+
123+
elif message.get("role") == "tool" and "tool_call_id" in message:
124+
for tool_call in tool_calls:
125+
if tool_call.get("call_id") == message.get("tool_call_id"):
126+
result = message.get("content", "")
127+
result_summary = result[:100] + "..." if len(result) > 100 else result
128+
print(f"Tool Result: {tool_call.get('name')} Return: {result_summary}")
129+
logger.info(f"Tool Result: {tool_call.get('name')} Return: {result_summary}")
130+
131+
print(f"Total tool calls found: {len(tool_calls)}")
132+
logger.info(f"Total tool calls found: {len(tool_calls)}")
133+
logger.info("========== Finished tool call analysis ==========")
134+
135+
with open("cooking_chat_history.json", "w", encoding="utf-8") as f:
136+
json.dump(chat_history, f, ensure_ascii=False, indent=2)
137+
138+
print("Records saved to cooking_chat_history.json")
139+
print("============ Analysis Complete ============\n")
140+
141+
142+
def run_cooking_companion():
143+
task = "I have chicken breast, broccoli, garlic, and pasta. I'm looking for a quick dinner recipe that's healthy. I'm also trying to reduce my sodium intake. Search the internet for a recipe, modify it for low sodium, and create a shopping list for any additional ingredients I need?"
144+
society = construct_cooking_society(task)
145+
answer, chat_history, token_count = run_society(society)
146+
147+
# Record tool usage history
148+
analyze_chat_history(chat_history)
149+
print(f"\033[94mAnswer: {answer}\033[0m")
150+
151+
152+
if __name__ == "__main__":
153+
run_cooking_companion()

0 commit comments

Comments
 (0)