mirror of
https://github.com/Significant-Gravitas/AutoGPT.git
synced 2026-01-30 01:18:07 -05:00
Merge branch 'master' into ddg-search
This commit is contained in:
@@ -74,30 +74,25 @@ def split_text(text, max_length=8192):
|
||||
yield "\n".join(current_chunk)
|
||||
|
||||
|
||||
def summarize_text(text, is_website=True):
|
||||
if text == "":
|
||||
def create_message(chunk, question):
|
||||
return {
|
||||
"role": "user",
|
||||
"content": f"\"\"\"{chunk}\"\"\" Using the above text, please answer the following question: \"{question}\" -- if the question cannot be answered using the text, please summarize the text."
|
||||
}
|
||||
|
||||
def summarize_text(text, question):
|
||||
if not text:
|
||||
return "Error: No text to summarize"
|
||||
|
||||
print("Text length: " + str(len(text)) + " characters")
|
||||
text_length = len(text)
|
||||
print(f"Text length: {text_length} characters")
|
||||
|
||||
summaries = []
|
||||
chunks = list(split_text(text))
|
||||
|
||||
for i, chunk in enumerate(chunks):
|
||||
print("Summarizing chunk " + str(i + 1) + " / " + str(len(chunks)))
|
||||
if is_website:
|
||||
messages = [
|
||||
{
|
||||
"role": "user",
|
||||
"content": "Please summarize the following website text, do not describe the general website, but instead concisely extract the specific information this subpage contains.: " +
|
||||
chunk},
|
||||
]
|
||||
else:
|
||||
messages = [
|
||||
{
|
||||
"role": "user",
|
||||
"content": "Please summarize the following text, focusing on extracting concise and specific information: " +
|
||||
chunk},
|
||||
]
|
||||
print(f"Summarizing chunk {i + 1} / {len(chunks)}")
|
||||
messages = [create_message(chunk, question)]
|
||||
|
||||
summary = create_chat_completion(
|
||||
model=cfg.fast_llm_model,
|
||||
@@ -105,25 +100,11 @@ def summarize_text(text, is_website=True):
|
||||
max_tokens=300,
|
||||
)
|
||||
summaries.append(summary)
|
||||
print("Summarized " + str(len(chunks)) + " chunks.")
|
||||
|
||||
print(f"Summarized {len(chunks)} chunks.")
|
||||
|
||||
combined_summary = "\n".join(summaries)
|
||||
|
||||
# Summarize the combined summary
|
||||
if is_website:
|
||||
messages = [
|
||||
{
|
||||
"role": "user",
|
||||
"content": "Please summarize the following website text, do not describe the general website, but instead concisely extract the specific information this subpage contains.: " +
|
||||
combined_summary},
|
||||
]
|
||||
else:
|
||||
messages = [
|
||||
{
|
||||
"role": "user",
|
||||
"content": "Please summarize the following text, focusing on extracting concise and specific infomation: " +
|
||||
combined_summary},
|
||||
]
|
||||
messages = [create_message(combined_summary, question)]
|
||||
|
||||
final_summary = create_chat_completion(
|
||||
model=cfg.fast_llm_model,
|
||||
@@ -131,4 +112,4 @@ def summarize_text(text, is_website=True):
|
||||
max_tokens=300,
|
||||
)
|
||||
|
||||
return final_summary
|
||||
return final_summary
|
||||
@@ -10,6 +10,9 @@ from file_operations import read_file, write_to_file, append_to_file, delete_fil
|
||||
from execute_code import execute_python_file
|
||||
from json_parser import fix_and_parse_json
|
||||
from duckduckgo_search import ddg
|
||||
from googleapiclient.discovery import build
|
||||
from googleapiclient.errors import HttpError
|
||||
|
||||
cfg = Config()
|
||||
|
||||
|
||||
@@ -44,7 +47,13 @@ def get_command(response):
|
||||
def execute_command(command_name, arguments):
|
||||
try:
|
||||
if command_name == "google":
|
||||
return google_search(arguments["input"])
|
||||
|
||||
# Check if the Google API key is set and use the official search method
|
||||
# If the API key is not set or has only whitespaces, use the unofficial search method
|
||||
if cfg.google_api_key and (cfg.google_api_key.strip() if cfg.google_api_key else None):
|
||||
return google_official_search(arguments["input"])
|
||||
else:
|
||||
return google_search(arguments["input"])
|
||||
elif command_name == "memory_add":
|
||||
return commit_memory(arguments["string"])
|
||||
elif command_name == "memory_del":
|
||||
@@ -63,7 +72,7 @@ def execute_command(command_name, arguments):
|
||||
elif command_name == "delete_agent":
|
||||
return delete_agent(arguments["key"])
|
||||
elif command_name == "get_text_summary":
|
||||
return get_text_summary(arguments["url"])
|
||||
return get_text_summary(arguments["url"], arguments["question"])
|
||||
elif command_name == "get_hyperlinks":
|
||||
return get_hyperlinks(arguments["url"])
|
||||
elif command_name == "read_file":
|
||||
@@ -75,7 +84,7 @@ def execute_command(command_name, arguments):
|
||||
elif command_name == "delete_file":
|
||||
return delete_file(arguments["file"])
|
||||
elif command_name == "browse_website":
|
||||
return browse_website(arguments["url"])
|
||||
return browse_website(arguments["url"], arguments["question"])
|
||||
# TODO: Change these to take in a file rather than pasted code, if
|
||||
# non-file is given, return instructions "Input should be a python
|
||||
# filepath, write your code to file and try again"
|
||||
@@ -108,9 +117,43 @@ def google_search(query, num_results=8):
|
||||
|
||||
return json.dumps(search_results, ensure_ascii=False, indent=4)
|
||||
|
||||
def google_official_search(query, num_results=8):
|
||||
from googleapiclient.discovery import build
|
||||
from googleapiclient.errors import HttpError
|
||||
import json
|
||||
|
||||
def browse_website(url):
|
||||
summary = get_text_summary(url)
|
||||
try:
|
||||
# Get the Google API key and Custom Search Engine ID from the config file
|
||||
api_key = cfg.google_api_key
|
||||
custom_search_engine_id = cfg.custom_search_engine_id
|
||||
|
||||
# Initialize the Custom Search API service
|
||||
service = build("customsearch", "v1", developerKey=api_key)
|
||||
|
||||
# Send the search query and retrieve the results
|
||||
result = service.cse().list(q=query, cx=custom_search_engine_id, num=num_results).execute()
|
||||
|
||||
# Extract the search result items from the response
|
||||
search_results = result.get("items", [])
|
||||
|
||||
# Create a list of only the URLs from the search results
|
||||
search_results_links = [item["link"] for item in search_results]
|
||||
|
||||
except HttpError as e:
|
||||
# Handle errors in the API call
|
||||
error_details = json.loads(e.content.decode())
|
||||
|
||||
# Check if the error is related to an invalid or missing API key
|
||||
if error_details.get("error", {}).get("code") == 403 and "invalid API key" in error_details.get("error", {}).get("message", ""):
|
||||
return "Error: The provided Google API key is invalid or missing."
|
||||
else:
|
||||
return f"Error: {e}"
|
||||
|
||||
# Return the list of search result URLs
|
||||
return search_results_links
|
||||
|
||||
def browse_website(url, question):
|
||||
summary = get_text_summary(url, question)
|
||||
links = get_hyperlinks(url)
|
||||
|
||||
# Limit links to 5
|
||||
@@ -122,9 +165,9 @@ def browse_website(url):
|
||||
return result
|
||||
|
||||
|
||||
def get_text_summary(url):
|
||||
def get_text_summary(url, question):
|
||||
text = browse.scrape_text(url)
|
||||
summary = browse.summarize_text(text)
|
||||
summary = browse.summarize_text(text, question)
|
||||
return """ "Result" : """ + summary
|
||||
|
||||
|
||||
|
||||
@@ -35,11 +35,13 @@ class Config(metaclass=Singleton):
|
||||
|
||||
self.openai_api_key = os.getenv("OPENAI_API_KEY")
|
||||
self.elevenlabs_api_key = os.getenv("ELEVENLABS_API_KEY")
|
||||
|
||||
self.google_api_key = os.getenv("GOOGLE_API_KEY")
|
||||
self.custom_search_engine_id = os.getenv("CUSTOM_SEARCH_ENGINE_ID")
|
||||
|
||||
# Initialize the OpenAI API client
|
||||
openai.api_key = self.openai_api_key
|
||||
|
||||
|
||||
def set_continuous_mode(self, value: bool):
|
||||
self.continuous_mode = value
|
||||
|
||||
@@ -59,10 +61,13 @@ class Config(metaclass=Singleton):
|
||||
self.smart_token_limit = value
|
||||
|
||||
def set_openai_api_key(self, value: str):
|
||||
self.apiopenai_api_key_key = value
|
||||
self.openai_api_key = value
|
||||
|
||||
def set_elevenlabs_api_key(self, value: str):
|
||||
self.elevenlabs_api_key = value
|
||||
|
||||
|
||||
|
||||
def set_google_api_key(self, value: str):
|
||||
self.google_api_key = value
|
||||
|
||||
def set_custom_search_engine_id(self, value: str):
|
||||
self.custom_search_engine_id = value
|
||||
@@ -1,6 +1,6 @@
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
SRC_DIR = Path(__file__).parent
|
||||
|
||||
def load_prompt():
|
||||
try:
|
||||
@@ -9,7 +9,7 @@ def load_prompt():
|
||||
data_dir = file_dir / "data"
|
||||
prompt_file = data_dir / "prompt.txt"
|
||||
# Load the promt from data/prompt.txt
|
||||
with open(prompt_file, "r") as prompt_file:
|
||||
with open(SRC_DIR/ "data/prompt.txt", "r") as prompt_file:
|
||||
prompt = prompt_file.read()
|
||||
|
||||
return prompt
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
CONSTRAINTS:
|
||||
|
||||
1. ~4000 word limit for memory. Your memory is short, so immidiately save important information to long term memory and code to files.
|
||||
1. ~4000 word limit for memory. Your memory is short, so immediately save important information to long term memory and code to files.
|
||||
2. No user assistance
|
||||
3. Exclusively use the commands listed in double quotes e.g. "command name"
|
||||
|
||||
COMMANDS:
|
||||
|
||||
@@ -9,7 +10,7 @@ COMMANDS:
|
||||
2. Memory Add: "memory_add", args: "string": "<string>"
|
||||
3. Memory Delete: "memory_del", args: "key": "<key>"
|
||||
4. Memory Overwrite: "memory_ovr", args: "key": "<key>", "string": "<string>"
|
||||
5. Browse Website: "browse_website", args: "url": "<url>"
|
||||
5. Browse Website: "browse_website", args: "url": "<url>", "question": "<what_you_want_to_find_on_website>"
|
||||
6. Start GPT Agent: "start_agent", args: "name": <name>, "task": "<short_task_desc>", "prompt": "<prompt>"
|
||||
7. Message GPT Agent: "message_agent", args: "key": "<key>", "message": "<message>"
|
||||
8. List GPT Agents: "list_agents", args: ""
|
||||
@@ -34,9 +35,9 @@ RESOURCES:
|
||||
PERFORMANCE EVALUATION:
|
||||
|
||||
1. Continuously review and analyze your actions to ensure you are performing to the best of your abilities.
|
||||
2. Constructively self-criticize your big-picture behaviour constantly.
|
||||
2. Constructively self-criticize your big-picture behavior constantly.
|
||||
3. Reflect on past decisions and strategies to refine your approach.
|
||||
4. Every command has a cost, so be smart and efficent. Aim to complete tasks in the least number of steps.
|
||||
4. Every command has a cost, so be smart and efficient. Aim to complete tasks in the least number of steps.
|
||||
|
||||
You should only respond in JSON format as described below
|
||||
|
||||
@@ -58,4 +59,4 @@ RESPONSE FORMAT:
|
||||
}
|
||||
}
|
||||
|
||||
Ensure the response can be parsed by Python json.loads
|
||||
Ensure the response can be parsed by Python json.loads
|
||||
|
||||
@@ -31,6 +31,9 @@ def read_file(filename):
|
||||
def write_to_file(filename, text):
|
||||
try:
|
||||
filepath = safe_join(working_directory, filename)
|
||||
directory = os.path.dirname(filepath)
|
||||
if not os.path.exists(directory):
|
||||
os.makedirs(directory)
|
||||
with open(filepath, "w") as f:
|
||||
f.write(text)
|
||||
return "File written to successfully."
|
||||
|
||||
104
scripts/main.py
104
scripts/main.py
@@ -52,65 +52,58 @@ def print_assistant_thoughts(assistant_reply):
|
||||
# Parse and print Assistant response
|
||||
assistant_reply_json = fix_and_parse_json(assistant_reply)
|
||||
|
||||
try:
|
||||
assistant_thoughts = assistant_reply_json.get("thoughts")
|
||||
if assistant_thoughts:
|
||||
assistant_thoughts_text = assistant_thoughts.get("text")
|
||||
assistant_thoughts_reasoning = assistant_thoughts.get("reasoning")
|
||||
assistant_thoughts_plan = assistant_thoughts.get("plan")
|
||||
assistant_thoughts_criticism = assistant_thoughts.get("criticism")
|
||||
assistant_thoughts_speak = assistant_thoughts.get("speak")
|
||||
else:
|
||||
assistant_thoughts_text = None
|
||||
assistant_thoughts_reasoning = None
|
||||
assistant_thoughts_plan = None
|
||||
assistant_thoughts_criticism = None
|
||||
assistant_thoughts_speak = None
|
||||
except Exception as e:
|
||||
assistant_thoughts_text = "The AI's response was unreadable."
|
||||
# Check if assistant_reply_json is a string and attempt to parse it into a JSON object
|
||||
if isinstance(assistant_reply_json, str):
|
||||
try:
|
||||
assistant_reply_json = json.loads(assistant_reply_json)
|
||||
except json.JSONDecodeError as e:
|
||||
print_to_console("Error: Invalid JSON\n", Fore.RED, assistant_reply)
|
||||
assistant_reply_json = {}
|
||||
|
||||
assistant_thoughts_reasoning = None
|
||||
assistant_thoughts_plan = None
|
||||
assistant_thoughts_speak = None
|
||||
assistant_thoughts_criticism = None
|
||||
assistant_thoughts = assistant_reply_json.get("thoughts", {})
|
||||
assistant_thoughts_text = assistant_thoughts.get("text")
|
||||
|
||||
if assistant_thoughts:
|
||||
assistant_thoughts_reasoning = assistant_thoughts.get("reasoning")
|
||||
assistant_thoughts_plan = assistant_thoughts.get("plan")
|
||||
assistant_thoughts_criticism = assistant_thoughts.get("criticism")
|
||||
assistant_thoughts_speak = assistant_thoughts.get("speak")
|
||||
|
||||
print_to_console(f"{ai_name.upper()} THOUGHTS:", Fore.YELLOW, assistant_thoughts_text)
|
||||
print_to_console("REASONING:", Fore.YELLOW, assistant_thoughts_reasoning)
|
||||
|
||||
print_to_console(
|
||||
f"{ai_name.upper()} THOUGHTS:",
|
||||
Fore.YELLOW,
|
||||
assistant_thoughts_text)
|
||||
print_to_console(
|
||||
"REASONING:",
|
||||
Fore.YELLOW,
|
||||
assistant_thoughts_reasoning)
|
||||
if assistant_thoughts_plan:
|
||||
print_to_console("PLAN:", Fore.YELLOW, "")
|
||||
if assistant_thoughts_plan:
|
||||
# If it's a list, join it into a string
|
||||
if isinstance(assistant_thoughts_plan, list):
|
||||
assistant_thoughts_plan = "\n".join(assistant_thoughts_plan)
|
||||
elif isinstance(assistant_thoughts_plan, dict):
|
||||
assistant_thoughts_plan = str(assistant_thoughts_plan)
|
||||
# Split the input_string using the newline character and dash
|
||||
|
||||
lines = assistant_thoughts_plan.split('\n')
|
||||
# If it's a list, join it into a string
|
||||
if isinstance(assistant_thoughts_plan, list):
|
||||
assistant_thoughts_plan = "\n".join(assistant_thoughts_plan)
|
||||
elif isinstance(assistant_thoughts_plan, dict):
|
||||
assistant_thoughts_plan = str(assistant_thoughts_plan)
|
||||
|
||||
# Iterate through the lines and print each one with a bullet
|
||||
# point
|
||||
for line in lines:
|
||||
# Remove any "-" characters from the start of the line
|
||||
line = line.lstrip("- ")
|
||||
print_to_console("- ", Fore.GREEN, line.strip())
|
||||
print_to_console(
|
||||
"CRITICISM:",
|
||||
Fore.YELLOW,
|
||||
assistant_thoughts_criticism)
|
||||
# Split the input_string using the newline character and dashes
|
||||
lines = assistant_thoughts_plan.split('\n')
|
||||
for line in lines:
|
||||
line = line.lstrip("- ")
|
||||
print_to_console("- ", Fore.GREEN, line.strip())
|
||||
|
||||
print_to_console("CRITICISM:", Fore.YELLOW, assistant_thoughts_criticism)
|
||||
# Speak the assistant's thoughts
|
||||
if cfg.speak_mode and assistant_thoughts_speak:
|
||||
speak.say_text(assistant_thoughts_speak)
|
||||
|
||||
except json.decoder.JSONDecodeError:
|
||||
print_to_console("Error: Invalid JSON\n", Fore.RED, assistant_reply)
|
||||
|
||||
# All other errors, return "Error: + error message"
|
||||
except Exception as e:
|
||||
call_stack = traceback.format_exc()
|
||||
print_to_console("Error: \n", Fore.RED, call_stack)
|
||||
|
||||
|
||||
def load_variables(config_file="config.yaml"):
|
||||
# Load variables from yaml file if it exists
|
||||
try:
|
||||
@@ -318,7 +311,7 @@ while True:
|
||||
Fore.CYAN,
|
||||
f"COMMAND = {Fore.CYAN}{command_name}{Style.RESET_ALL} ARGUMENTS = {Fore.CYAN}{arguments}{Style.RESET_ALL}")
|
||||
print(
|
||||
"Enter 'y' to authorise command or 'n' to exit program...",
|
||||
f"Enter 'y' to authorise command or 'n' to exit program, or enter feedback for {ai_name}...",
|
||||
flush=True)
|
||||
while True:
|
||||
console_input = input(Fore.MAGENTA + "Input:" + Style.RESET_ALL)
|
||||
@@ -329,16 +322,18 @@ while True:
|
||||
user_input = "EXIT"
|
||||
break
|
||||
else:
|
||||
continue
|
||||
user_input = console_input
|
||||
command_name = "human_feedback"
|
||||
break
|
||||
|
||||
if user_input != "GENERATE NEXT COMMAND JSON":
|
||||
print("Exiting...", flush=True)
|
||||
break
|
||||
|
||||
print_to_console(
|
||||
if user_input == "GENERATE NEXT COMMAND JSON":
|
||||
print_to_console(
|
||||
"-=-=-=-=-=-=-= COMMAND AUTHORISED BY USER -=-=-=-=-=-=-=",
|
||||
Fore.MAGENTA,
|
||||
"")
|
||||
elif user_input == "EXIT":
|
||||
print("Exiting...", flush=True)
|
||||
break
|
||||
else:
|
||||
# Print command
|
||||
print_to_console(
|
||||
@@ -347,10 +342,12 @@ while True:
|
||||
f"COMMAND = {Fore.CYAN}{command_name}{Style.RESET_ALL} ARGUMENTS = {Fore.CYAN}{arguments}{Style.RESET_ALL}")
|
||||
|
||||
# Execute command
|
||||
if command_name.lower() != "error":
|
||||
result = f"Command {command_name} returned: {cmd.execute_command(command_name, arguments)}"
|
||||
else:
|
||||
if command_name.lower() == "error":
|
||||
result = f"Command {command_name} threw the following error: " + arguments
|
||||
elif command_name == "human_feedback":
|
||||
result = f"Human feedback: {user_input}"
|
||||
else:
|
||||
result = f"Command {command_name} returned: {cmd.execute_command(command_name, arguments)}"
|
||||
|
||||
# Check if there's a result from the command append it to the message
|
||||
# history
|
||||
@@ -362,3 +359,4 @@ while True:
|
||||
chat.create_chat_message(
|
||||
"system", "Unable to execute command"))
|
||||
print_to_console("SYSTEM: ", Fore.YELLOW, "Unable to execute command")
|
||||
|
||||
|
||||
@@ -3,6 +3,8 @@ from playsound import playsound
|
||||
import requests
|
||||
from config import Config
|
||||
cfg = Config()
|
||||
import gtts
|
||||
|
||||
|
||||
# TODO: Nicer names for these ids
|
||||
voices = ["ErXwobaYiN019PkySvjV", "EXAVITQu4vr4xnSDxMaL"]
|
||||
@@ -12,10 +14,9 @@ tts_headers = {
|
||||
"xi-api-key": cfg.elevenlabs_api_key
|
||||
}
|
||||
|
||||
def say_text(text, voice_index=0):
|
||||
def eleven_labs_speech(text, voice_index=0):
|
||||
tts_url = "https://api.elevenlabs.io/v1/text-to-speech/{voice_id}".format(
|
||||
voice_id=voices[voice_index])
|
||||
|
||||
formatted_message = {"text": text}
|
||||
response = requests.post(
|
||||
tts_url, headers=tts_headers, json=formatted_message)
|
||||
@@ -24,8 +25,24 @@ def say_text(text, voice_index=0):
|
||||
with open("speech.mpeg", "wb") as f:
|
||||
f.write(response.content)
|
||||
playsound("speech.mpeg")
|
||||
# Delete audio file
|
||||
os.remove("speech.mpeg")
|
||||
return True
|
||||
else:
|
||||
print("Request failed with status code:", response.status_code)
|
||||
print("Response content:", response.content)
|
||||
return False
|
||||
|
||||
def gtts_speech(text):
|
||||
tts = gtts.gTTS(text)
|
||||
tts.save("speech.mp3")
|
||||
playsound("speech.mp3")
|
||||
os.remove("speech.mp3")
|
||||
|
||||
def say_text(text, voice_index=0):
|
||||
if not cfg.elevenlabs_api_key:
|
||||
gtts_speech(text)
|
||||
else:
|
||||
success = eleven_labs_speech()
|
||||
if not success:
|
||||
gtts_speech(text)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user