Skip to content

Commit 64e8bdb

Browse files
Create BabyCatAGI.py
Uploading another mod of OG BabyAGI (original commit). Just because it's easier to experiment with framework as a simple script. Would love to hear feedback - this one might be getting stable enough to discuss pulling into core.
1 parent 60b605d commit 64e8bdb

File tree

1 file changed

+320
-0
lines changed

1 file changed

+320
-0
lines changed

classic/BabyCatAGI.py

+320
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,320 @@
1+
###### This is a modified version of OG BabyAGI, called BabyCatAGI (future modifications will follow the pattern "Baby<animal>AGI"). This version requires GPT-4, it's very slow, and often errors out.######
2+
######IMPORTANT NOTE: I'm sharing this as a framework to build on top of (with lots of errors for improvement), to facilitate discussion around how to improve these. This is NOT for people who are looking for a complete solution that's ready to use. ######
3+
4+
import openai
5+
import time
6+
import requests
7+
from bs4 import BeautifulSoup
8+
from collections import deque
9+
from typing import Dict, List
10+
import re
11+
import ast
12+
import json
13+
from serpapi import GoogleSearch
14+
15+
### SET THESE 4 VARIABLES ##############################
16+
17+
# Add your API keys here
18+
OPENAI_API_KEY = ""
19+
SERPAPI_API_KEY = "" #If you include SERPAPI KEY, this will enable web-search. If you don't, it will autoatically remove web-search capability.
20+
21+
# Set variables
22+
OBJECTIVE = "Research experts at scaling NextJS and their Twitter accounts."
23+
YOUR_FIRST_TASK = "Develop a task list." #you can provide additional instructions here regarding the task list.
24+
25+
### UP TO HERE ##############################
26+
27+
# Configure OpenAI and SerpAPI client
28+
openai.api_key = OPENAI_API_KEY
29+
if SERPAPI_API_KEY:
30+
serpapi_client = GoogleSearch({"api_key": SERPAPI_API_KEY})
31+
websearch_var = "[web-search] "
32+
else:
33+
websearch_var = ""
34+
35+
# Initialize task list
36+
task_list = []
37+
38+
# Initialize session_summary
39+
session_summary = ""
40+
41+
### Task list functions ##############################
42+
def add_task(task: Dict):
43+
task_list.append(task)
44+
45+
def get_task_by_id(task_id: int):
46+
for task in task_list:
47+
if task["id"] == task_id:
48+
return task
49+
return None
50+
51+
def get_completed_tasks():
52+
return [task for task in task_list if task["status"] == "complete"]
53+
54+
55+
# Print task list and session summary
56+
def print_tasklist():
57+
print("\033[95m\033[1m" + "\n*****TASK LIST*****\n" + "\033[0m")
58+
for t in task_list:
59+
dependent_task = ""
60+
if t['dependent_task_ids']:
61+
dependent_task = f"\033[31m<dependencies: {', '.join([f'#{dep_id}' for dep_id in t['dependent_task_ids']])}>\033[0m"
62+
status_color = "\033[32m" if t['status'] == "complete" else "\033[31m"
63+
print(f"\033[1m{t['id']}\033[0m: {t['task']} {status_color}[{t['status']}]\033[0m \033[93m[{t['tool']}] {dependent_task}\033[0m")
64+
65+
### Tool functions ##############################
66+
def text_completion_tool(prompt: str):
67+
messages = [
68+
{"role": "user", "content": prompt}
69+
]
70+
71+
response = openai.ChatCompletion.create(
72+
model="gpt-3.5-turbo",
73+
messages=messages,
74+
temperature=0.2,
75+
max_tokens=1500,
76+
top_p=1,
77+
frequency_penalty=0,
78+
presence_penalty=0
79+
)
80+
81+
return response.choices[0].message['content'].strip()
82+
83+
84+
def web_search_tool(query: str):
85+
search_params = {
86+
"engine": "google",
87+
"q": query,
88+
"api_key": SERPAPI_API_KEY,
89+
"num":5 #edit this up or down for more results, though higher often results in OpenAI rate limits
90+
}
91+
search_results = GoogleSearch(search_params)
92+
search_results = search_results.get_dict()
93+
try:
94+
search_results = search_results["organic_results"]
95+
except:
96+
search_results = {}
97+
search_results = simplify_search_results(search_results)
98+
print("\033[90m\033[3m" + "Completed search. Now scraping results.\n" + "\033[0m")
99+
results = "";
100+
# Loop through the search results
101+
for result in search_results:
102+
# Extract the URL from the result
103+
url = result.get('link')
104+
# Call the web_scrape_tool function with the URL
105+
print("\033[90m\033[3m" + "Scraping: "+url+"" + "...\033[0m")
106+
content = web_scrape_tool(url, task)
107+
print("\033[90m\033[3m" +str(content[0:100])[0:100]+"...\n" + "\033[0m")
108+
results += str(content)+". "
109+
110+
111+
return results
112+
113+
114+
def simplify_search_results(search_results):
115+
simplified_results = []
116+
for result in search_results:
117+
simplified_result = {
118+
"position": result.get("position"),
119+
"title": result.get("title"),
120+
"link": result.get("link"),
121+
"snippet": result.get("snippet")
122+
}
123+
simplified_results.append(simplified_result)
124+
return simplified_results
125+
126+
127+
def web_scrape_tool(url: str, task:str):
128+
content = fetch_url_content(url)
129+
if content is None:
130+
return None
131+
132+
text = extract_text(content)
133+
print("\033[90m\033[3m"+"Scrape completed. Length:" +str(len(text))+".Now extracting relevant info..."+"...\033[0m")
134+
info = extract_relevant_info(OBJECTIVE, text[0:5000], task)
135+
links = extract_links(content)
136+
137+
#result = f"{info} URLs: {', '.join(links)}"
138+
result = info
139+
140+
return result
141+
142+
headers = {
143+
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.81 Safari/537.36"
144+
}
145+
146+
def fetch_url_content(url: str):
147+
try:
148+
response = requests.get(url, headers=headers, timeout=10)
149+
response.raise_for_status()
150+
return response.content
151+
except requests.exceptions.RequestException as e:
152+
print(f"Error while fetching the URL: {e}")
153+
return ""
154+
155+
def extract_links(content: str):
156+
soup = BeautifulSoup(content, "html.parser")
157+
links = [link.get('href') for link in soup.findAll('a', attrs={'href': re.compile("^https?://")})]
158+
return links
159+
160+
def extract_text(content: str):
161+
soup = BeautifulSoup(content, "html.parser")
162+
text = soup.get_text(strip=True)
163+
return text
164+
165+
166+
167+
def extract_relevant_info(objective, large_string, task):
168+
chunk_size = 3000
169+
overlap = 500
170+
notes = ""
171+
172+
for i in range(0, len(large_string), chunk_size - overlap):
173+
chunk = large_string[i:i + chunk_size]
174+
175+
messages = [
176+
{"role": "system", "content": f"Objective: {objective}\nCurrent Task:{task}"},
177+
{"role": "user", "content": f"Analyze the following text and extract information relevant to our objective and current task, and only information relevant to our objective and current task. If there is no relevant information do not say that there is no relevant informaiton related to our objective. ### Then, update or start our notes provided here (keep blank if currently blank): {notes}.### Text to analyze: {chunk}.### Updated Notes:"}
178+
]
179+
180+
response = openai.ChatCompletion.create(
181+
model="gpt-3.5-turbo",
182+
messages=messages,
183+
max_tokens=800,
184+
n=1,
185+
stop="###",
186+
temperature=0.7,
187+
)
188+
189+
notes += response.choices[0].message['content'].strip()+". ";
190+
191+
return notes
192+
193+
### Agent functions ##############################
194+
195+
196+
def execute_task(task, task_list, OBJECTIVE):
197+
global task_id_counter
198+
# Check if dependent_task_ids is not empty
199+
if task["dependent_task_ids"]:
200+
all_dependent_tasks_complete = True
201+
for dep_id in task["dependent_task_ids"]:
202+
dependent_task = get_task_by_id(dep_id)
203+
if not dependent_task or dependent_task["status"] != "complete":
204+
all_dependent_tasks_complete = False
205+
break
206+
207+
208+
# Execute task
209+
print("\033[92m\033[1m"+"\n*****NEXT TASK*****\n"+"\033[0m\033[0m")
210+
print(str(task['id'])+": "+str(task['task'])+" ["+str(task['tool']+"]"))
211+
task_prompt = f"Complete your assigned task based on the objective and only based on information provided in the dependent task output, if provided. Your objective: {OBJECTIVE}. Your task: {task['task']}"
212+
if task["dependent_task_ids"]:
213+
dependent_tasks_output = ""
214+
for dep_id in task["dependent_task_ids"]:
215+
dependent_task_output = get_task_by_id(dep_id)["output"]
216+
dependent_task_output = dependent_task_output[0:2000]
217+
dependent_tasks_output += f" {dependent_task_output}"
218+
task_prompt += f" Your dependent tasks output: {dependent_tasks_output}\n OUTPUT:"
219+
220+
# Use tool to complete the task
221+
if task["tool"] == "text-completion":
222+
task_output = text_completion_tool(task_prompt)
223+
elif task["tool"] == "web-search":
224+
task_output = web_search_tool(str(task['task']))
225+
elif task["tool"] == "web-scrape":
226+
task_output = web_scrape_tool(str(task['task']))
227+
228+
# Find task index in the task_list
229+
task_index = next((i for i, t in enumerate(task_list) if t["id"] == task["id"]), None)
230+
231+
# Mark task as complete and save output
232+
task_list[task_index]["status"] = "complete"
233+
task_list[task_index]["output"] = task_output
234+
235+
# Print task output
236+
print("\033[93m\033[1m"+"\nTask Output:"+"\033[0m\033[0m")
237+
print(task_output)
238+
239+
# Add task output to session_summary
240+
global session_summary
241+
session_summary += f"\n\nTask {task['id']} - {task['task']}:\n{task_output}"
242+
243+
244+
245+
task_list = []
246+
247+
def task_creation_agent(objective: str) -> List[Dict]:
248+
global task_list
249+
minified_task_list = [{k: v for k, v in task.items() if k != "result"} for task in task_list]
250+
251+
prompt = (
252+
f"You are a task creation AI tasked with creating a list of tasks as a JSON array, considering the ultimate objective of your team: {OBJECTIVE}. "
253+
f"Create new tasks based on the objective. Limit tasks types to those that can be completed with the available tools listed below. Task description should be detailed."
254+
f"Current tool option is [text-completion] {websearch_var} and only." # web-search is added automatically if SERPAPI exists
255+
f"For tasks using [web-search], provide the search query, and only the search query to use (eg. not 'research waterproof shoes, but 'waterproof shoes')"
256+
f"dependent_task_ids should always be an empty array, or an array of numbers representing the task ID it should pull results from."
257+
f"Make sure all task IDs are in chronological order.\n"
258+
f"The last step is always to provide a final summary report including tasks executed and summary of knowledge acquired.\n"
259+
f"Do not create any summarizing steps outside of the last step..\n"
260+
f"An example of the desired output format is: "
261+
"[{\"id\": 1, \"task\": \"https://untapped.vc\", \"tool\": \"web-scrape\", \"dependent_task_ids\": [], \"status\": \"incomplete\", \"result\": null, \"result_summary\": null}, {\"id\": 2, \"task\": \"Consider additional insights that can be reasoned from the results of...\", \"tool\": \"text-completion\", \"dependent_task_ids\": [1], \"status\": \"incomplete\", \"result\": null, \"result_summary\": null}, {\"id\": 3, \"task\": \"Untapped Capital\", \"tool\": \"web-search\", \"dependent_task_ids\": [], \"status\": \"incomplete\", \"result\": null, \"result_summary\": null}].\n"
262+
f"JSON TASK LIST="
263+
)
264+
265+
print("\033[90m\033[3m" + "\nInitializing...\n" + "\033[0m")
266+
print("\033[90m\033[3m" + "Analyzing objective...\n" + "\033[0m")
267+
print("\033[90m\033[3m" + "Running task creation agent...\n" + "\033[0m")
268+
response = openai.ChatCompletion.create(
269+
model="gpt-4",
270+
messages=[
271+
{
272+
"role": "system",
273+
"content": "You are a task creation AI."
274+
},
275+
{
276+
"role": "user",
277+
"content": prompt
278+
}
279+
],
280+
temperature=0,
281+
max_tokens=1500,
282+
top_p=1,
283+
frequency_penalty=0,
284+
presence_penalty=0
285+
)
286+
287+
# Extract the content of the assistant's response and parse it as JSON
288+
result = response["choices"][0]["message"]["content"]
289+
print("\033[90m\033[3m" + "\nDone!\n" + "\033[0m")
290+
try:
291+
task_list = json.loads(result)
292+
except Exception as error:
293+
print(error)
294+
295+
return task_list
296+
297+
##### START MAIN LOOP########
298+
299+
#Print OBJECTIVE
300+
print("\033[96m\033[1m"+"\n*****OBJECTIVE*****\n"+"\033[0m\033[0m")
301+
print(OBJECTIVE)
302+
303+
# Initialize task_id_counter
304+
task_id_counter = 1
305+
306+
# Run the task_creation_agent to create initial tasks
307+
task_list = task_creation_agent(OBJECTIVE)
308+
print_tasklist()
309+
310+
# Execute tasks in order
311+
while len(task_list) > 0:
312+
for task in task_list:
313+
if task["status"] == "incomplete":
314+
execute_task(task, task_list, OBJECTIVE)
315+
print_tasklist()
316+
break
317+
318+
# Print session summary
319+
print("\033[96m\033[1m"+"\n*****SESSION SUMMARY*****\n"+"\033[0m\033[0m")
320+
print(session_summary)

0 commit comments

Comments
 (0)