mirror of
https://github.com/Significant-Gravitas/AutoGPT.git
synced 2026-01-09 15:17:59 -05:00
Merge branch 'master' into add_ingest_documents_script
This commit is contained in:
23
.devcontainer/Dockerfile
Normal file
23
.devcontainer/Dockerfile
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
# [Choice] Python version (use -bullseye variants on local arm64/Apple Silicon): 3, 3.10, 3.9, 3.8, 3.7, 3.6, 3-bullseye, 3.10-bullseye, 3.9-bullseye, 3.8-bullseye, 3.7-bullseye, 3.6-bullseye, 3-buster, 3.10-buster, 3.9-buster, 3.8-buster, 3.7-buster, 3.6-buster
|
||||||
|
ARG VARIANT=3-bullseye
|
||||||
|
FROM python:3.8
|
||||||
|
|
||||||
|
RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \
|
||||||
|
# Remove imagemagick due to https://security-tracker.debian.org/tracker/CVE-2019-10131
|
||||||
|
&& apt-get purge -y imagemagick imagemagick-6-common
|
||||||
|
|
||||||
|
# Temporary: Upgrade python packages due to https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-40897
|
||||||
|
# They are installed by the base image (python) which does not have the patch.
|
||||||
|
RUN python3 -m pip install --upgrade setuptools
|
||||||
|
|
||||||
|
# [Optional] If your pip requirements rarely change, uncomment this section to add them to the image.
|
||||||
|
# COPY requirements.txt /tmp/pip-tmp/
|
||||||
|
# RUN pip3 --disable-pip-version-check --no-cache-dir install -r /tmp/pip-tmp/requirements.txt \
|
||||||
|
# && rm -rf /tmp/pip-tmp
|
||||||
|
|
||||||
|
# [Optional] Uncomment this section to install additional OS packages.
|
||||||
|
# RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \
|
||||||
|
# && apt-get -y install --no-install-recommends <your-package-list-here>
|
||||||
|
|
||||||
|
# [Optional] Uncomment this line to install global node packages.
|
||||||
|
# RUN su vscode -c "source /usr/local/share/nvm/nvm.sh && npm install -g <your-package-here>" 2>&1
|
||||||
39
.devcontainer/devcontainer.json
Normal file
39
.devcontainer/devcontainer.json
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
{
|
||||||
|
"build": {
|
||||||
|
"dockerfile": "./Dockerfile",
|
||||||
|
"context": "."
|
||||||
|
},
|
||||||
|
"features": {
|
||||||
|
"ghcr.io/devcontainers/features/common-utils:2": {
|
||||||
|
"installZsh": "true",
|
||||||
|
"username": "vscode",
|
||||||
|
"userUid": "1000",
|
||||||
|
"userGid": "1000",
|
||||||
|
"upgradePackages": "true"
|
||||||
|
},
|
||||||
|
"ghcr.io/devcontainers/features/python:1": "none",
|
||||||
|
"ghcr.io/devcontainers/features/node:1": "none",
|
||||||
|
"ghcr.io/devcontainers/features/git:1": {
|
||||||
|
"version": "latest",
|
||||||
|
"ppa": "false"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// Configure tool-specific properties.
|
||||||
|
"customizations": {
|
||||||
|
// Configure properties specific to VS Code.
|
||||||
|
"vscode": {
|
||||||
|
// Set *default* container specific settings.json values on container create.
|
||||||
|
"settings": {
|
||||||
|
"python.defaultInterpreterPath": "/usr/local/bin/python"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// Use 'forwardPorts' to make a list of ports inside the container available locally.
|
||||||
|
// "forwardPorts": [],
|
||||||
|
|
||||||
|
// Use 'postCreateCommand' to run commands after the container is created.
|
||||||
|
// "postCreateCommand": "pip3 install --user -r requirements.txt",
|
||||||
|
|
||||||
|
// Set `remoteUser` to `root` to connect as root instead. More info: https://aka.ms/vscode-remote/containers/non-root.
|
||||||
|
"remoteUser": "vscode"
|
||||||
|
}
|
||||||
@@ -102,6 +102,10 @@ CUSTOM_SEARCH_ENGINE_ID=your-custom-search-engine-id
|
|||||||
# USE_MAC_OS_TTS - Use Mac OS TTS or not (Default: False)
|
# USE_MAC_OS_TTS - Use Mac OS TTS or not (Default: False)
|
||||||
USE_MAC_OS_TTS=False
|
USE_MAC_OS_TTS=False
|
||||||
|
|
||||||
|
### STREAMELEMENTS
|
||||||
|
# USE_BRIAN_TTS - Use Brian TTS or not (Default: False)
|
||||||
|
USE_BRIAN_TTS=False
|
||||||
|
|
||||||
### ELEVENLABS
|
### ELEVENLABS
|
||||||
# ELEVENLABS_API_KEY - Eleven Labs API key (Example: my-elevenlabs-api-key)
|
# ELEVENLABS_API_KEY - Eleven Labs API key (Example: my-elevenlabs-api-key)
|
||||||
# ELEVENLABS_VOICE_1_ID - Eleven Labs voice 1 ID (Example: my-voice-id-1)
|
# ELEVENLABS_VOICE_1_ID - Eleven Labs voice 1 ID (Example: my-voice-id-1)
|
||||||
|
|||||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -17,6 +17,7 @@ last_run_ai_settings.yaml
|
|||||||
auto-gpt.json
|
auto-gpt.json
|
||||||
log.txt
|
log.txt
|
||||||
log-ingestion.txt
|
log-ingestion.txt
|
||||||
|
logs
|
||||||
|
|
||||||
# Coverage reports
|
# Coverage reports
|
||||||
.coverage
|
.coverage
|
||||||
|
|||||||
28
Dockerfile
28
Dockerfile
@@ -1,7 +1,23 @@
|
|||||||
|
# Use an official Python base image from the Docker Hub
|
||||||
FROM python:3.11-slim
|
FROM python:3.11-slim
|
||||||
ENV PIP_NO_CACHE_DIR=yes
|
|
||||||
WORKDIR /app
|
# Set environment variables
|
||||||
COPY requirements.txt .
|
ENV PIP_NO_CACHE_DIR=yes \
|
||||||
RUN pip install -r requirements.txt
|
PYTHONUNBUFFERED=1 \
|
||||||
COPY scripts/ .
|
PYTHONDONTWRITEBYTECODE=1
|
||||||
ENTRYPOINT ["python", "main.py"]
|
|
||||||
|
# Create a non-root user and set permissions
|
||||||
|
RUN useradd --create-home appuser
|
||||||
|
WORKDIR /home/appuser
|
||||||
|
RUN chown appuser:appuser /home/appuser
|
||||||
|
USER appuser
|
||||||
|
|
||||||
|
# Copy the requirements.txt file and install the requirements
|
||||||
|
COPY --chown=appuser:appuser requirements.txt .
|
||||||
|
RUN pip install --no-cache-dir --user -r requirements.txt
|
||||||
|
|
||||||
|
# Copy the application files
|
||||||
|
COPY --chown=appuser:appuser scripts/ .
|
||||||
|
|
||||||
|
# Set the entrypoint
|
||||||
|
ENTRYPOINT ["python", "main.py"]
|
||||||
31
README.md
31
README.md
@@ -66,13 +66,16 @@ Your support is greatly appreciated
|
|||||||
|
|
||||||
## 📋 Requirements
|
## 📋 Requirements
|
||||||
|
|
||||||
- [Python 3.8 or later](https://www.tutorialspoint.com/how-to-install-python-in-windows)
|
- environments(just choose one)
|
||||||
|
- [vscode + devcontainer](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers): It has been configured in the .devcontainer folder and can be used directly
|
||||||
|
- [Python 3.8 or later](https://www.tutorialspoint.com/how-to-install-python-in-windows)
|
||||||
- [OpenAI API key](https://platform.openai.com/account/api-keys)
|
- [OpenAI API key](https://platform.openai.com/account/api-keys)
|
||||||
- [PINECONE API key](https://www.pinecone.io/)
|
|
||||||
|
|
||||||
Optional:
|
Optional:
|
||||||
|
|
||||||
- [ElevenLabs Key](https://elevenlabs.io/) (If you want the AI to speak)
|
- [PINECONE API key](https://www.pinecone.io/) (If you want Pinecone backed memory)
|
||||||
|
- ElevenLabs Key (If you want the AI to speak)
|
||||||
|
|
||||||
## 💾 Installation
|
## 💾 Installation
|
||||||
|
|
||||||
@@ -123,8 +126,8 @@ pip install -r requirements.txt
|
|||||||
python scripts/main.py
|
python scripts/main.py
|
||||||
```
|
```
|
||||||
|
|
||||||
2. After each of AUTO-GPT's actions, type "NEXT COMMAND" to authorise them to continue.
|
2. After each of action, enter 'y' to authorise command, 'y -N' to run N continuous commands, 'n' to exit program, or enter additional feedback for the AI.
|
||||||
3. To exit the program, type "exit" and press Enter.
|
|
||||||
|
|
||||||
### Logs
|
### Logs
|
||||||
|
|
||||||
@@ -155,9 +158,10 @@ To use the `google_official_search` command, you need to set up your Google API
|
|||||||
4. Go to the [APIs & Services Dashboard](https://console.cloud.google.com/apis/dashboard) and click "Enable APIs and Services". Search for "Custom Search API" and click on it, then click "Enable".
|
4. Go to the [APIs & Services Dashboard](https://console.cloud.google.com/apis/dashboard) and click "Enable APIs and Services". Search for "Custom Search API" and click on it, then click "Enable".
|
||||||
5. Go to the [Credentials](https://console.cloud.google.com/apis/credentials) page and click "Create Credentials". Choose "API Key".
|
5. Go to the [Credentials](https://console.cloud.google.com/apis/credentials) page and click "Create Credentials". Choose "API Key".
|
||||||
6. Copy the API key and set it as an environment variable named `GOOGLE_API_KEY` on your machine. See setting up environment variables below.
|
6. Copy the API key and set it as an environment variable named `GOOGLE_API_KEY` on your machine. See setting up environment variables below.
|
||||||
7. Go to the [Custom Search Engine](https://cse.google.com/cse/all) page and click "Add".
|
7. [Enable](https://console.developers.google.com/apis/api/customsearch.googleapis.com) the Custom Search API on your project. (Might need to wait few minutes to propagate)
|
||||||
8. Set up your search engine by following the prompts. You can choose to search the entire web or specific sites.
|
8. Go to the [Custom Search Engine](https://cse.google.com/cse/all) page and click "Add".
|
||||||
9. Once you've created your search engine, click on "Control Panel" and then "Basics". Copy the "Search engine ID" and set it as an environment variable named `CUSTOM_SEARCH_ENGINE_ID` on your machine. See setting up environment variables below.
|
9. Set up your search engine by following the prompts. You can choose to search the entire web or specific sites.
|
||||||
|
10. Once you've created your search engine, click on "Control Panel" and then "Basics". Copy the "Search engine ID" and set it as an environment variable named `CUSTOM_SEARCH_ENGINE_ID` on your machine. See setting up environment variables below.
|
||||||
|
|
||||||
_Remember that your free daily custom search quota allows only up to 100 searches. To increase this limit, you need to assign a billing account to the project to profit from up to 10K daily searches._
|
_Remember that your free daily custom search quota allows only up to 100 searches. To increase this limit, you need to assign a billing account to the project to profit from up to 10K daily searches._
|
||||||
|
|
||||||
@@ -226,7 +230,10 @@ Pinecone enables the storage of vast amounts of vector-based memory, allowing fo
|
|||||||
|
|
||||||
### Setting up environment variables
|
### Setting up environment variables
|
||||||
|
|
||||||
Simply set them in the `.env` file.
|
In the `.env` file set:
|
||||||
|
- `PINECONE_API_KEY`
|
||||||
|
- `PINECONE_ENV` (something like: us-east4-gcp)
|
||||||
|
- `MEMORY_BACKEND=pinecone`
|
||||||
|
|
||||||
Alternatively, you can set them from the command line (advanced):
|
Alternatively, you can set them from the command line (advanced):
|
||||||
|
|
||||||
@@ -235,7 +242,7 @@ For Windows Users:
|
|||||||
```
|
```
|
||||||
setx PINECONE_API_KEY "YOUR_PINECONE_API_KEY"
|
setx PINECONE_API_KEY "YOUR_PINECONE_API_KEY"
|
||||||
setx PINECONE_ENV "Your pinecone region" # something like: us-east4-gcp
|
setx PINECONE_ENV "Your pinecone region" # something like: us-east4-gcp
|
||||||
|
setx MEMORY_BACKEND "pinecone"
|
||||||
```
|
```
|
||||||
|
|
||||||
For macOS and Linux users:
|
For macOS and Linux users:
|
||||||
@@ -243,7 +250,7 @@ For macOS and Linux users:
|
|||||||
```
|
```
|
||||||
export PINECONE_API_KEY="YOUR_PINECONE_API_KEY"
|
export PINECONE_API_KEY="YOUR_PINECONE_API_KEY"
|
||||||
export PINECONE_ENV="Your pinecone region" # something like: us-east4-gcp
|
export PINECONE_ENV="Your pinecone region" # something like: us-east4-gcp
|
||||||
|
export MEMORY_BACKEND="pinecone"
|
||||||
```
|
```
|
||||||
|
|
||||||
## Setting Your Cache Type
|
## Setting Your Cache Type
|
||||||
@@ -404,4 +411,4 @@ flake8 scripts/ tests/
|
|||||||
|
|
||||||
# Or, if you want to run flake8 with the same configuration as the CI:
|
# Or, if you want to run flake8 with the same configuration as the CI:
|
||||||
flake8 scripts/ tests/ --select E303,W293,W291,W292,E305,E231,E302
|
flake8 scripts/ tests/ --select E303,W293,W291,W292,E305,E231,E302
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -70,8 +70,8 @@ class AIConfig:
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
config = {"ai_name": self.ai_name, "ai_role": self.ai_role, "ai_goals": self.ai_goals}
|
config = {"ai_name": self.ai_name, "ai_role": self.ai_role, "ai_goals": self.ai_goals}
|
||||||
with open(config_file, "w") as file:
|
with open(config_file, "w", encoding='utf-8') as file:
|
||||||
yaml.dump(config, file)
|
yaml.dump(config, file, allow_unicode=True)
|
||||||
|
|
||||||
def construct_full_prompt(self) -> str:
|
def construct_full_prompt(self) -> str:
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ def call_ai_function(function, args, description, model=None):
|
|||||||
model = cfg.smart_llm_model
|
model = cfg.smart_llm_model
|
||||||
# For each arg, if any are None, convert to "None":
|
# For each arg, if any are None, convert to "None":
|
||||||
args = [str(arg) if arg is not None else "None" for arg in args]
|
args = [str(arg) if arg is not None else "None" for arg in args]
|
||||||
# parse args to comma seperated string
|
# parse args to comma separated string
|
||||||
args = ", ".join(args)
|
args = ", ".join(args)
|
||||||
messages = [
|
messages = [
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -62,6 +62,9 @@ class Config(metaclass=Singleton):
|
|||||||
self.use_mac_os_tts = False
|
self.use_mac_os_tts = False
|
||||||
self.use_mac_os_tts = os.getenv("USE_MAC_OS_TTS")
|
self.use_mac_os_tts = os.getenv("USE_MAC_OS_TTS")
|
||||||
|
|
||||||
|
self.use_brian_tts = False
|
||||||
|
self.use_brian_tts = os.getenv("USE_BRIAN_TTS")
|
||||||
|
|
||||||
self.google_api_key = os.getenv("GOOGLE_API_KEY")
|
self.google_api_key = os.getenv("GOOGLE_API_KEY")
|
||||||
self.custom_search_engine_id = os.getenv("CUSTOM_SEARCH_ENGINE_ID")
|
self.custom_search_engine_id = os.getenv("CUSTOM_SEARCH_ENGINE_ID")
|
||||||
|
|
||||||
|
|||||||
@@ -24,7 +24,8 @@ For console handler: simulates typing
|
|||||||
class Logger(metaclass=Singleton):
|
class Logger(metaclass=Singleton):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
# create log directory if it doesn't exist
|
# create log directory if it doesn't exist
|
||||||
log_dir = os.path.join('..', 'logs')
|
this_files_dir_path = os.path.dirname(__file__)
|
||||||
|
log_dir = os.path.join(this_files_dir_path, '../logs')
|
||||||
if not os.path.exists(log_dir):
|
if not os.path.exists(log_dir):
|
||||||
os.makedirs(log_dir)
|
os.makedirs(log_dir)
|
||||||
|
|
||||||
|
|||||||
284
scripts/main.py
284
scripts/main.py
@@ -129,60 +129,6 @@ def print_assistant_thoughts(assistant_reply):
|
|||||||
logger.error("Error: \n", call_stack)
|
logger.error("Error: \n", call_stack)
|
||||||
|
|
||||||
|
|
||||||
def load_variables(config_file="config.yaml"):
|
|
||||||
"""Load variables from yaml file if it exists, otherwise prompt the user for input"""
|
|
||||||
try:
|
|
||||||
with open(config_file) as file:
|
|
||||||
config = yaml.load(file, Loader=yaml.FullLoader)
|
|
||||||
ai_name = config.get("ai_name")
|
|
||||||
ai_role = config.get("ai_role")
|
|
||||||
ai_goals = config.get("ai_goals")
|
|
||||||
except FileNotFoundError:
|
|
||||||
ai_name = ""
|
|
||||||
ai_role = ""
|
|
||||||
ai_goals = []
|
|
||||||
|
|
||||||
# Prompt the user for input if config file is missing or empty values
|
|
||||||
if not ai_name:
|
|
||||||
ai_name = utils.clean_input("Name your AI: ")
|
|
||||||
if ai_name == "":
|
|
||||||
ai_name = "Entrepreneur-GPT"
|
|
||||||
|
|
||||||
if not ai_role:
|
|
||||||
ai_role = utils.clean_input(f"{ai_name} is: ")
|
|
||||||
if ai_role == "":
|
|
||||||
ai_role = "an AI designed to autonomously develop and run businesses with the sole goal of increasing your net worth."
|
|
||||||
|
|
||||||
if not ai_goals:
|
|
||||||
print("Enter up to 5 goals for your AI: ")
|
|
||||||
print("For example: \nIncrease net worth, Grow Twitter Account, Develop and manage multiple businesses autonomously'")
|
|
||||||
print("Enter nothing to load defaults, enter nothing when finished.")
|
|
||||||
ai_goals = []
|
|
||||||
for i in range(5):
|
|
||||||
ai_goal = utils.clean_input(f"Goal {i+1}: ")
|
|
||||||
if ai_goal == "":
|
|
||||||
break
|
|
||||||
ai_goals.append(ai_goal)
|
|
||||||
if len(ai_goals) == 0:
|
|
||||||
ai_goals = ["Increase net worth", "Grow Twitter Account", "Develop and manage multiple businesses autonomously"]
|
|
||||||
|
|
||||||
# Save variables to yaml file
|
|
||||||
config = {"ai_name": ai_name, "ai_role": ai_role, "ai_goals": ai_goals}
|
|
||||||
with open(config_file, "w") as file:
|
|
||||||
documents = yaml.dump(config, file)
|
|
||||||
|
|
||||||
prompt = get_prompt()
|
|
||||||
prompt_start = """Your decisions must always be made independently without seeking user assistance. Play to your strengths as an LLM and pursue simple strategies with no legal complications."""
|
|
||||||
|
|
||||||
# Construct full prompt
|
|
||||||
full_prompt = f"You are {ai_name}, {ai_role}\n{prompt_start}\n\nGOALS:\n\n"
|
|
||||||
for i, goal in enumerate(ai_goals):
|
|
||||||
full_prompt += f"{i+1}. {goal}\n"
|
|
||||||
|
|
||||||
full_prompt += f"\n\n{prompt}"
|
|
||||||
return full_prompt
|
|
||||||
|
|
||||||
|
|
||||||
def construct_prompt():
|
def construct_prompt():
|
||||||
"""Construct the prompt for the AI to respond to"""
|
"""Construct the prompt for the AI to respond to"""
|
||||||
config = AIConfig.load()
|
config = AIConfig.load()
|
||||||
@@ -318,10 +264,6 @@ def parse_arguments():
|
|||||||
logger.typewriter_log("GPT4 Only Mode: ", Fore.GREEN, "ENABLED")
|
logger.typewriter_log("GPT4 Only Mode: ", Fore.GREEN, "ENABLED")
|
||||||
cfg.set_fast_llm_model(cfg.smart_llm_model)
|
cfg.set_fast_llm_model(cfg.smart_llm_model)
|
||||||
|
|
||||||
if args.debug:
|
|
||||||
logger.typewriter_log("Debug Mode: ", Fore.GREEN, "ENABLED")
|
|
||||||
cfg.set_debug_mode(True)
|
|
||||||
|
|
||||||
if args.memory_type:
|
if args.memory_type:
|
||||||
supported_memory = get_supported_memory_backends()
|
supported_memory = get_supported_memory_backends()
|
||||||
chosen = args.memory_type
|
chosen = args.memory_type
|
||||||
@@ -351,110 +293,148 @@ def main():
|
|||||||
# this is particularly important for indexing and referencing pinecone memory
|
# this is particularly important for indexing and referencing pinecone memory
|
||||||
memory = get_memory(cfg, init=True)
|
memory = get_memory(cfg, init=True)
|
||||||
print('Using memory of type: ' + memory.__class__.__name__)
|
print('Using memory of type: ' + memory.__class__.__name__)
|
||||||
# Interaction Loop
|
agent = Agent(
|
||||||
loop_count = 0
|
ai_name=ai_name,
|
||||||
while True:
|
memory=memory,
|
||||||
# Discontinue if continuous limit is reached
|
full_message_history=full_message_history,
|
||||||
loop_count += 1
|
next_action_count=next_action_count,
|
||||||
if cfg.continuous_mode and cfg.continuous_limit > 0 and loop_count > cfg.continuous_limit:
|
prompt=prompt,
|
||||||
logger.typewriter_log("Continuous Limit Reached: ", Fore.YELLOW, f"{cfg.continuous_limit}")
|
user_input=user_input
|
||||||
break
|
)
|
||||||
|
agent.start_interaction_loop()
|
||||||
|
|
||||||
# Send message to AI, get response
|
|
||||||
with Spinner("Thinking... "):
|
|
||||||
assistant_reply = chat.chat_with_ai(
|
|
||||||
prompt,
|
|
||||||
user_input,
|
|
||||||
full_message_history,
|
|
||||||
memory,
|
|
||||||
cfg.fast_token_limit) # TODO: This hardcodes the model to use GPT3.5. Make this an argument
|
|
||||||
|
|
||||||
# Print Assistant thoughts
|
class Agent:
|
||||||
print_assistant_thoughts(assistant_reply)
|
"""Agent class for interacting with Auto-GPT.
|
||||||
|
|
||||||
# Get command name and arguments
|
Attributes:
|
||||||
try:
|
ai_name: The name of the agent.
|
||||||
command_name, arguments = cmd.get_command(
|
memory: The memory object to use.
|
||||||
attempt_to_fix_json_by_finding_outermost_brackets(assistant_reply))
|
full_message_history: The full message history.
|
||||||
if cfg.speak_mode:
|
next_action_count: The number of actions to execute.
|
||||||
speak.say_text(f"I want to execute {command_name}")
|
prompt: The prompt to use.
|
||||||
except Exception as e:
|
user_input: The user input.
|
||||||
logger.error("Error: \n", str(e))
|
|
||||||
|
|
||||||
if not cfg.continuous_mode and next_action_count == 0:
|
"""
|
||||||
### GET USER AUTHORIZATION TO EXECUTE COMMAND ###
|
def __init__(self,
|
||||||
# Get key press: Prompt the user to press enter to continue or escape
|
ai_name,
|
||||||
# to exit
|
memory,
|
||||||
user_input = ""
|
full_message_history,
|
||||||
logger.typewriter_log(
|
next_action_count,
|
||||||
"NEXT ACTION: ",
|
prompt,
|
||||||
Fore.CYAN,
|
user_input):
|
||||||
f"COMMAND = {Fore.CYAN}{command_name}{Style.RESET_ALL} ARGUMENTS = {Fore.CYAN}{arguments}{Style.RESET_ALL}")
|
self.ai_name = ai_name
|
||||||
print(
|
self.memory = memory
|
||||||
f"Enter 'y' to authorise command, 'y -N' to run N continuous commands, 'n' to exit program, or enter feedback for {ai_name}...",
|
self.full_message_history = full_message_history
|
||||||
flush=True)
|
self.next_action_count = next_action_count
|
||||||
while True:
|
self.prompt = prompt
|
||||||
console_input = utils.clean_input(Fore.MAGENTA + "Input:" + Style.RESET_ALL)
|
self.user_input = user_input
|
||||||
if console_input.lower().rstrip() == "y":
|
|
||||||
user_input = "GENERATE NEXT COMMAND JSON"
|
|
||||||
break
|
|
||||||
elif console_input.lower().startswith("y -"):
|
|
||||||
try:
|
|
||||||
next_action_count = abs(int(console_input.split(" ")[1]))
|
|
||||||
user_input = "GENERATE NEXT COMMAND JSON"
|
|
||||||
except ValueError:
|
|
||||||
print("Invalid input format. Please enter 'y -n' where n is the number of continuous tasks.")
|
|
||||||
continue
|
|
||||||
break
|
|
||||||
elif console_input.lower() == "n":
|
|
||||||
user_input = "EXIT"
|
|
||||||
break
|
|
||||||
else:
|
|
||||||
user_input = console_input
|
|
||||||
command_name = "human_feedback"
|
|
||||||
break
|
|
||||||
|
|
||||||
if user_input == "GENERATE NEXT COMMAND JSON":
|
def start_interaction_loop(self):
|
||||||
logger.typewriter_log(
|
# Interaction Loop
|
||||||
"-=-=-=-=-=-=-= COMMAND AUTHORISED BY USER -=-=-=-=-=-=-=",
|
loop_count = 0
|
||||||
Fore.MAGENTA,
|
while True:
|
||||||
"")
|
# Discontinue if continuous limit is reached
|
||||||
elif user_input == "EXIT":
|
loop_count += 1
|
||||||
print("Exiting...", flush=True)
|
if cfg.continuous_mode and cfg.continuous_limit > 0 and loop_count > cfg.continuous_limit:
|
||||||
|
logger.typewriter_log("Continuous Limit Reached: ", Fore.YELLOW, f"{cfg.continuous_limit}")
|
||||||
break
|
break
|
||||||
else:
|
|
||||||
# Print command
|
|
||||||
logger.typewriter_log(
|
|
||||||
"NEXT ACTION: ",
|
|
||||||
Fore.CYAN,
|
|
||||||
f"COMMAND = {Fore.CYAN}{command_name}{Style.RESET_ALL} ARGUMENTS = {Fore.CYAN}{arguments}{Style.RESET_ALL}")
|
|
||||||
|
|
||||||
# Execute command
|
# Send message to AI, get response
|
||||||
if command_name is not None and command_name.lower().startswith("error"):
|
with Spinner("Thinking... "):
|
||||||
result = f"Command {command_name} threw the following error: " + arguments
|
assistant_reply = chat.chat_with_ai(
|
||||||
elif command_name == "human_feedback":
|
self.prompt,
|
||||||
result = f"Human feedback: {user_input}"
|
self.user_input,
|
||||||
else:
|
self.full_message_history,
|
||||||
result = f"Command {command_name} returned: {cmd.execute_command(command_name, arguments)}"
|
self.memory,
|
||||||
if next_action_count > 0:
|
cfg.fast_token_limit) # TODO: This hardcodes the model to use GPT3.5. Make this an argument
|
||||||
next_action_count -= 1
|
|
||||||
|
|
||||||
memory_to_add = f"Assistant Reply: {assistant_reply} " \
|
# Print Assistant thoughts
|
||||||
f"\nResult: {result} " \
|
print_assistant_thoughts(assistant_reply)
|
||||||
f"\nHuman Feedback: {user_input} "
|
|
||||||
|
|
||||||
memory.add(memory_to_add)
|
# Get command name and arguments
|
||||||
|
try:
|
||||||
|
command_name, arguments = cmd.get_command(
|
||||||
|
attempt_to_fix_json_by_finding_outermost_brackets(assistant_reply))
|
||||||
|
if cfg.speak_mode:
|
||||||
|
speak.say_text(f"I want to execute {command_name}")
|
||||||
|
except Exception as e:
|
||||||
|
logger.error("Error: \n", str(e))
|
||||||
|
|
||||||
# Check if there's a result from the command append it to the message
|
if not cfg.continuous_mode and self.next_action_count == 0:
|
||||||
# history
|
### GET USER AUTHORIZATION TO EXECUTE COMMAND ###
|
||||||
if result is not None:
|
# Get key press: Prompt the user to press enter to continue or escape
|
||||||
full_message_history.append(chat.create_chat_message("system", result))
|
# to exit
|
||||||
logger.typewriter_log("SYSTEM: ", Fore.YELLOW, result)
|
self.user_input = ""
|
||||||
else:
|
logger.typewriter_log(
|
||||||
full_message_history.append(
|
"NEXT ACTION: ",
|
||||||
chat.create_chat_message(
|
Fore.CYAN,
|
||||||
"system", "Unable to execute command"))
|
f"COMMAND = {Fore.CYAN}{command_name}{Style.RESET_ALL} ARGUMENTS = {Fore.CYAN}{arguments}{Style.RESET_ALL}")
|
||||||
logger.typewriter_log("SYSTEM: ", Fore.YELLOW, "Unable to execute command")
|
print(
|
||||||
|
f"Enter 'y' to authorise command, 'y -N' to run N continuous commands, 'n' to exit program, or enter feedback for {self.ai_name}...",
|
||||||
|
flush=True)
|
||||||
|
while True:
|
||||||
|
console_input = utils.clean_input(Fore.MAGENTA + "Input:" + Style.RESET_ALL)
|
||||||
|
if console_input.lower().rstrip() == "y":
|
||||||
|
self.user_input = "GENERATE NEXT COMMAND JSON"
|
||||||
|
break
|
||||||
|
elif console_input.lower().startswith("y -"):
|
||||||
|
try:
|
||||||
|
self.next_action_count = abs(int(console_input.split(" ")[1]))
|
||||||
|
self.user_input = "GENERATE NEXT COMMAND JSON"
|
||||||
|
except ValueError:
|
||||||
|
print("Invalid input format. Please enter 'y -n' where n is the number of continuous tasks.")
|
||||||
|
continue
|
||||||
|
break
|
||||||
|
elif console_input.lower() == "n":
|
||||||
|
self.user_input = "EXIT"
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
self.user_input = console_input
|
||||||
|
command_name = "human_feedback"
|
||||||
|
break
|
||||||
|
|
||||||
|
if self.user_input == "GENERATE NEXT COMMAND JSON":
|
||||||
|
logger.typewriter_log(
|
||||||
|
"-=-=-=-=-=-=-= COMMAND AUTHORISED BY USER -=-=-=-=-=-=-=",
|
||||||
|
Fore.MAGENTA,
|
||||||
|
"")
|
||||||
|
elif self.user_input == "EXIT":
|
||||||
|
print("Exiting...", flush=True)
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
# Print command
|
||||||
|
logger.typewriter_log(
|
||||||
|
"NEXT ACTION: ",
|
||||||
|
Fore.CYAN,
|
||||||
|
f"COMMAND = {Fore.CYAN}{command_name}{Style.RESET_ALL} ARGUMENTS = {Fore.CYAN}{arguments}{Style.RESET_ALL}")
|
||||||
|
|
||||||
|
# Execute command
|
||||||
|
if command_name is not None and command_name.lower().startswith("error"):
|
||||||
|
result = f"Command {command_name} threw the following error: " + arguments
|
||||||
|
elif command_name == "human_feedback":
|
||||||
|
result = f"Human feedback: {self.user_input}"
|
||||||
|
else:
|
||||||
|
result = f"Command {command_name} returned: {cmd.execute_command(command_name, arguments)}"
|
||||||
|
if self.next_action_count > 0:
|
||||||
|
self.next_action_count -= 1
|
||||||
|
|
||||||
|
memory_to_add = f"Assistant Reply: {assistant_reply} " \
|
||||||
|
f"\nResult: {result} " \
|
||||||
|
f"\nHuman Feedback: {self.user_input} "
|
||||||
|
|
||||||
|
self.memory.add(memory_to_add)
|
||||||
|
|
||||||
|
# Check if there's a result from the command append it to the message
|
||||||
|
# history
|
||||||
|
if result is not None:
|
||||||
|
self.full_message_history.append(chat.create_chat_message("system", result))
|
||||||
|
logger.typewriter_log("SYSTEM: ", Fore.YELLOW, result)
|
||||||
|
else:
|
||||||
|
self.full_message_history.append(
|
||||||
|
chat.create_chat_message(
|
||||||
|
"system", "Unable to execute command"))
|
||||||
|
logger.typewriter_log("SYSTEM: ", Fore.YELLOW, "Unable to execute command")
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
|||||||
@@ -53,6 +53,24 @@ def eleven_labs_speech(text, voice_index=0):
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def brian_speech(text):
|
||||||
|
"""Speak text using Brian with the streamelements API"""
|
||||||
|
tts_url = f"https://api.streamelements.com/kappa/v2/speech?voice=Brian&text={text}"
|
||||||
|
response = requests.get(tts_url)
|
||||||
|
|
||||||
|
if response.status_code == 200:
|
||||||
|
with mutex_lock:
|
||||||
|
with open("speech.mp3", "wb") as f:
|
||||||
|
f.write(response.content)
|
||||||
|
playsound("speech.mp3")
|
||||||
|
os.remove("speech.mp3")
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
print("Request failed with status code:", response.status_code)
|
||||||
|
print("Response content:", response.content)
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
def gtts_speech(text):
|
def gtts_speech(text):
|
||||||
tts = gtts.gTTS(text)
|
tts = gtts.gTTS(text)
|
||||||
with mutex_lock:
|
with mutex_lock:
|
||||||
@@ -76,7 +94,11 @@ def say_text(text, voice_index=0):
|
|||||||
def speak():
|
def speak():
|
||||||
if not cfg.elevenlabs_api_key:
|
if not cfg.elevenlabs_api_key:
|
||||||
if cfg.use_mac_os_tts == 'True':
|
if cfg.use_mac_os_tts == 'True':
|
||||||
macos_tts_speech(text, voice_index)
|
macos_tts_speech(text)
|
||||||
|
elif cfg.use_brian_tts == 'True':
|
||||||
|
success = brian_speech(text)
|
||||||
|
if not success:
|
||||||
|
gtts_speech(text)
|
||||||
else:
|
else:
|
||||||
gtts_speech(text)
|
gtts_speech(text)
|
||||||
else:
|
else:
|
||||||
|
|||||||
@@ -17,10 +17,10 @@ class Spinner:
|
|||||||
def spin(self):
|
def spin(self):
|
||||||
"""Spin the spinner"""
|
"""Spin the spinner"""
|
||||||
while self.running:
|
while self.running:
|
||||||
sys.stdout.write(next(self.spinner) + " " + self.message + "\r")
|
sys.stdout.write(f"{next(self.spinner)} {self.message}\r")
|
||||||
sys.stdout.flush()
|
sys.stdout.flush()
|
||||||
time.sleep(self.delay)
|
time.sleep(self.delay)
|
||||||
sys.stdout.write('\r' + ' ' * (len(self.message) + 2) + '\r')
|
sys.stdout.write(f"\r{' ' * (len(self.message) + 2)}\r")
|
||||||
|
|
||||||
def __enter__(self):
|
def __enter__(self):
|
||||||
"""Start the spinner"""
|
"""Start the spinner"""
|
||||||
@@ -32,5 +32,5 @@ class Spinner:
|
|||||||
"""Stop the spinner"""
|
"""Stop the spinner"""
|
||||||
self.running = False
|
self.running = False
|
||||||
self.spinner_thread.join()
|
self.spinner_thread.join()
|
||||||
sys.stdout.write('\r' + ' ' * (len(self.message) + 2) + '\r')
|
sys.stdout.write(f"\r{' ' * (len(self.message) + 2)}\r")
|
||||||
sys.stdout.flush()
|
sys.stdout.flush()
|
||||||
|
|||||||
Reference in New Issue
Block a user