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