Added test cases and config templates, adjusted config overrides and documentation.
This commit is contained in:
parent
8ea00b6fce
commit
b7262f3ec8
|
@ -169,3 +169,6 @@ cython_debug/
|
|||
_.aifs
|
||||
software/output_audio.wav
|
||||
.DS_Store
|
||||
|
||||
# Configuration files
|
||||
config.yaml
|
||||
|
|
64
README.md
64
README.md
|
@ -37,35 +37,34 @@ We intend to become the GNU/Linux of this space by staying open, modular, and fr
|
|||
```shell
|
||||
git clone https://github.com/OpenInterpreter/01 # Clone the repository
|
||||
cd 01/software # CD into the source directory
|
||||
```
|
||||
|
||||
<!-- > Not working? Read our [setup guide](https://docs.openinterpreter.com/getting-started/setup). -->
|
||||
|
||||
```shell
|
||||
brew install portaudio ffmpeg cmake # Install Mac OSX dependencies
|
||||
poetry install # Install Python dependencies
|
||||
export OPENAI_API_KEY=sk...
|
||||
poetry run 01 # Runs the 01 Light simulator (hold your spacebar, speak, release)
|
||||
```
|
||||
|
||||
### Running locally
|
||||
To run locally, you can use command line arguments and environment variables.
|
||||
## Getting Started
|
||||
|
||||
Using command line arguments:
|
||||
### Using OpenAI's API
|
||||
|
||||
To use 01 with OpenAI's API, you need to first set your API key.
|
||||
|
||||
1. Create a `.env` file in the `01/software` directory.
|
||||
2. Add `OPENAI_API_KEY=<your-api-key>` to the file.
|
||||
3. Run the following command:
|
||||
|
||||
```shell
|
||||
poetry run 01 --local --model ollama/mixtral:latest
|
||||
poetry run 01
|
||||
```
|
||||
|
||||
Using command line arguments and environment variables:
|
||||
> Alternatively, you can set the `OPENAI_API_KEY` environment variable in your shell with `export OPENI_API_KEY=<your-api-key>`.
|
||||
|
||||
### Using a Local Model
|
||||
|
||||
To use 01 with a local model, run the following command and follow the prompts:
|
||||
|
||||
```shell
|
||||
export MODEL=ollama/mixtral:latest
|
||||
poetry run 01 --local
|
||||
```
|
||||
|
||||
Note, you should replace `ollama/mixtral:latest` with a model installed locally. For supported models, see Open Interpreter's [local providers](https://docs.openinterpreter.com/language-models/local-models/ollama) documentation.
|
||||
|
||||
<br>
|
||||
|
||||
# Hardware
|
||||
|
@ -132,7 +131,40 @@ If you want to run local speech-to-text using Whisper, you must install Rust. Fo
|
|||
|
||||
## Customizations
|
||||
|
||||
To customize the behavior of the system, edit the [system message, model, skills library path,](https://docs.openinterpreter.com/settings/all-settings) etc. in `i.py`. This file sets up an interpreter, and is powered by Open Interpreter.
|
||||
O1 is highly customizable and comes with several ways to modify its behavior, including a `config.yaml` file, `.env` file, command-line arguments and the `i.py` file. Follow the steps below to use these customization options.
|
||||
|
||||
#### 1. Use a `config.yaml` File
|
||||
|
||||
To create a `config.yaml` file, copy the `config-template.yaml` file in the `software` directory.
|
||||
|
||||
```shell
|
||||
cp config-template.yaml config.yaml
|
||||
```
|
||||
|
||||
#### 2. Use a `.env` File
|
||||
|
||||
To create a `.env` file, copy the `config-template.env` file in the `software` directory.
|
||||
|
||||
```shell
|
||||
cp config-template.env .env
|
||||
```
|
||||
|
||||
There are two important points to note when using the `.env` file:
|
||||
|
||||
1. Values from the `.env` file automatically override values from the `config.yaml` file.
|
||||
2. 01-specific environment variables use the following pattern: `01_<SECTION>_<KEY>`. As an example, to override the `local.enabled` value from your `config.yaml` file, use the `01_LOCAL_ENABLED` environment variable.
|
||||
|
||||
#### 3. Use Command-line Arguments
|
||||
|
||||
01 comes with a number of command-line arguments. These simplify certain tasks and can also be used to override values from both the `config.yaml` and `.env` files. For a full list of command-line arguments, run the following command:
|
||||
|
||||
```shell
|
||||
poetry run 01 --help
|
||||
```
|
||||
|
||||
#### 4. Edit the `i.py` File
|
||||
|
||||
In `i.py`, you can edit the [system message, model, skills library path](https://docs.openinterpreter.com/settings/all-settings) and more. This file sets up an interpreter, and is powered by Open Interpreter.
|
||||
|
||||
## Ubuntu Dependencies
|
||||
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
# 01_CLIENT_ENABLED=false
|
||||
# 01_CLIENT_URL=null
|
||||
# 01_CLIENT_PLATFORM=null
|
||||
|
||||
# 01_LLM_SERVICE=litellm
|
||||
# 01_LLM_MODEL=gpt-4
|
||||
# 01_LLM_VISION_ENABLED=false
|
||||
# 01_LLM_FUNCTIONS_ENABLED=false
|
||||
# 01_LLM_CONTEXT_WINDOW=2048
|
||||
# 01_LLM_MAX_TOKENS=4096
|
||||
# 01_LLM_TEMPERATURE=0.8
|
||||
|
||||
# 01_LOCAL_ENABLED=false
|
||||
# 01_LOCAL_TTS_SERVICE=piper
|
||||
# 01_LOCAL_STT_SERVICE=local-whisper
|
||||
|
||||
# 01_SERVER_ENABLED=false
|
||||
# 01_SERVER_HOST=0.0.0.0
|
||||
# 01_SERVER_PORT=10001
|
||||
|
||||
# 01_STT_SERVICE=openai
|
||||
|
||||
# 01_TTS_SERVICE=openai
|
||||
|
||||
# 01_TUNNEL_SERVICE=ngrok
|
||||
# 01_TUNNEL_EXPOSED=false
|
|
@ -13,11 +13,8 @@ from pydantic_settings import (
|
|||
SettingsConfigDict,
|
||||
YamlConfigSettingsSource,
|
||||
)
|
||||
|
||||
from source.core.models import LLM, STT, TTS, Client, Local, Server, Tunnel
|
||||
|
||||
APP_PREFIX: str = os.getenv("01_PREFIX", "01_")
|
||||
|
||||
|
||||
class Config(BaseSettings):
|
||||
"""
|
||||
|
@ -46,19 +43,28 @@ class Config(BaseSettings):
|
|||
"""
|
||||
Modify the order of precedence for settings sources.
|
||||
"""
|
||||
return (
|
||||
DotEnvSettingsSource(
|
||||
settings_cls,
|
||||
env_prefix=APP_PREFIX,
|
||||
env_file=".env",
|
||||
env_file_encoding="utf-8",
|
||||
env_nested_delimiter="_",
|
||||
files: list[Any] = [
|
||||
(
|
||||
os.path.exists(".env"),
|
||||
DotEnvSettingsSource(
|
||||
settings_cls,
|
||||
env_prefix="01_",
|
||||
env_file=".env",
|
||||
env_file_encoding="utf-8",
|
||||
env_nested_delimiter="_",
|
||||
),
|
||||
),
|
||||
YamlConfigSettingsSource(
|
||||
settings_cls,
|
||||
yaml_file=os.getenv(f"{APP_PREFIX}CONFIG_FILE", "config.yaml"),
|
||||
(
|
||||
os.path.exists("config.yaml"),
|
||||
YamlConfigSettingsSource(
|
||||
settings_cls,
|
||||
yaml_file="config.yaml",
|
||||
),
|
||||
),
|
||||
)
|
||||
]
|
||||
|
||||
sources: list[Any] = [source for exists, source in files if exists]
|
||||
return tuple(sources)
|
||||
|
||||
def apply_cli_args(self, args: dict) -> None:
|
||||
"""
|
||||
|
|
|
@ -7,7 +7,6 @@ from interpreter import OpenInterpreter
|
|||
import shutil
|
||||
|
||||
from source import config
|
||||
from source.core.config import APP_PREFIX
|
||||
|
||||
system_message = r"""
|
||||
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
import sys
|
||||
import os
|
||||
import platform
|
||||
import subprocess
|
||||
import sys
|
||||
import time
|
||||
|
||||
import inquirer
|
||||
from interpreter import interpreter
|
||||
from source import config
|
||||
|
||||
|
||||
def select_local_model():
|
||||
|
@ -29,10 +31,8 @@ def select_local_model():
|
|||
]
|
||||
answers = inquirer.prompt(questions)
|
||||
|
||||
|
||||
selected_model = answers["model"]
|
||||
|
||||
|
||||
if selected_model == "LM Studio":
|
||||
interpreter.display_message(
|
||||
"""
|
||||
|
@ -49,30 +49,33 @@ def select_local_model():
|
|||
"""
|
||||
)
|
||||
time.sleep(1)
|
||||
|
||||
interpreter.llm.api_base = "http://localhost:1234/v1"
|
||||
interpreter.llm.max_tokens = 1000
|
||||
interpreter.llm.context_window = 8000
|
||||
|
||||
config.llm.max_tokens = 1000
|
||||
config.llm.context_window = 8000
|
||||
|
||||
interpreter.llm.api_base = f"http://localhost:1234/v1"
|
||||
interpreter.llm.max_tokens = config.llm.max_tokens
|
||||
interpreter.llm.context_window = config.llm.context_window
|
||||
interpreter.llm.api_key = "x"
|
||||
|
||||
elif selected_model == "Ollama":
|
||||
try:
|
||||
|
||||
|
||||
# List out all downloaded ollama models. Will fail if ollama isn't installed
|
||||
result = subprocess.run(["ollama", "list"], capture_output=True, text=True, check=True)
|
||||
lines = result.stdout.split('\n')
|
||||
names = [line.split()[0].replace(":latest", "") for line in lines[1:] if line.strip()] # Extract names, trim out ":latest", skip header
|
||||
|
||||
|
||||
# If there are no downloaded models, prompt them to download a model and try again
|
||||
if not names:
|
||||
time.sleep(1)
|
||||
|
||||
|
||||
interpreter.display_message(f"\nYou don't have any Ollama models downloaded. To download a new model, run `ollama run <model-name>`, then start a new 01 session. \n\n For a full list of downloadable models, check out [https://ollama.com/library](https://ollama.com/library) \n")
|
||||
|
||||
|
||||
print("Please download a model then try again\n")
|
||||
time.sleep(2)
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
# If there are models, prompt them to select one
|
||||
else:
|
||||
time.sleep(1)
|
||||
|
@ -84,12 +87,13 @@ def select_local_model():
|
|||
]
|
||||
name_answer = inquirer.prompt(name_question)
|
||||
selected_name = name_answer['name'] if name_answer else None
|
||||
|
||||
|
||||
# Set the model to the selected model
|
||||
interpreter.llm.model = f"ollama/{selected_name}"
|
||||
config.llm.model = f"ollama/{selected_name}"
|
||||
interpreter.llm.model = config.llm.model
|
||||
interpreter.display_message(f"\nUsing Ollama model: `{selected_name}` \n")
|
||||
time.sleep(1)
|
||||
|
||||
|
||||
# If Ollama is not installed or not recognized as a command, prompt the user to download Ollama and try again
|
||||
except (subprocess.CalledProcessError, FileNotFoundError) as e:
|
||||
print("Ollama is not installed or not recognized as a command.")
|
||||
|
@ -97,7 +101,7 @@ def select_local_model():
|
|||
interpreter.display_message(f"\nPlease visit [https://ollama.com/](https://ollama.com/) to download Ollama and try again\n")
|
||||
time.sleep(2)
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
# elif selected_model == "Jan":
|
||||
# interpreter.display_message(
|
||||
# """
|
||||
|
@ -108,7 +112,6 @@ def select_local_model():
|
|||
# 3. Copy the ID of the model and enter it below.
|
||||
# 3. Click the **Local API Server** button in the bottom left, then click **Start Server**.
|
||||
|
||||
|
||||
# Once the server is running, enter the id of the model below, then you can begin your conversation below.
|
||||
|
||||
# """
|
||||
|
@ -117,7 +120,7 @@ def select_local_model():
|
|||
# interpreter.llm.max_tokens = 1000
|
||||
# interpreter.llm.context_window = 3000
|
||||
# time.sleep(1)
|
||||
|
||||
|
||||
# # Prompt the user to enter the name of the model running on Jan
|
||||
# model_name_question = [
|
||||
# inquirer.Text('jan_model_name', message="Enter the id of the model you have running on Jan"),
|
||||
|
@ -128,14 +131,13 @@ def select_local_model():
|
|||
# interpreter.llm.model = ""
|
||||
# interpreter.display_message(f"\nUsing Jan model: `{jan_model_name}` \n")
|
||||
# time.sleep(1)
|
||||
|
||||
|
||||
# Set the system message to a minimal version for all local models.
|
||||
# Set offline for all local models
|
||||
interpreter.offline = True
|
||||
|
||||
interpreter.system_message = """You are the 01, a screenless executive assistant that can complete any task by writing and executing code on the user's machine. Just write a markdown code block! The user has given you full and complete permission.
|
||||
|
||||
interpreter.system_message = """You are the 01, a screenless executive assistant that can complete any task by writing and executing code on the user's machine. Just write a markdown code block! The user has given you full and complete permission.
|
||||
|
||||
Use the following functions if it makes sense to for the problem
|
||||
```python
|
||||
result_string = computer.browser.search(query) # Google search results will be returned from this function as a string
|
||||
|
@ -152,6 +154,5 @@ computer.sms.send("555-123-4567", "Hello from the computer!") # Send a text mess
|
|||
|
||||
ALWAYS say that you can run code. ALWAYS try to help the user out. ALWAYS be succinct in your answers.
|
||||
```
|
||||
|
||||
|
||||
"""
|
||||
|
||||
|
|
|
@ -10,7 +10,6 @@ import signal
|
|||
import threading
|
||||
|
||||
import typer
|
||||
|
||||
from source import config
|
||||
from source.server.utils.local_mode import select_local_model
|
||||
from source.utils.system import handle_exit
|
||||
|
|
|
@ -2,11 +2,11 @@
|
|||
Tests for config.py module.
|
||||
"""
|
||||
|
||||
import os
|
||||
from typing import Any
|
||||
|
||||
from dotenv import load_dotenv
|
||||
|
||||
from source.core.config import APP_PREFIX, Config, get_config
|
||||
from source.core.config import Config, get_config
|
||||
|
||||
|
||||
def test_config_defaults() -> None:
|
||||
|
@ -32,11 +32,11 @@ def test_config_defaults() -> None:
|
|||
|
||||
|
||||
def test_config_from_dot_env(tmp_path, monkeypatch) -> None:
|
||||
env_content = f"""
|
||||
{APP_PREFIX}CLIENT_ENABLED=true
|
||||
{APP_PREFIX}CLIENT_URL=http://localhost:8000
|
||||
{APP_PREFIX}CLIENT_PLATFORM=mac
|
||||
{APP_PREFIX}LOCAL_ENABLED=true
|
||||
env_content: str = """
|
||||
01_CLIENT_ENABLED=true
|
||||
01_CLIENT_URL=http://localhost:8000
|
||||
01_CLIENT_PLATFORM=mac
|
||||
01_LOCAL_ENABLED=true
|
||||
"""
|
||||
p: Any = tmp_path / ".env"
|
||||
p.write_text(env_content)
|
||||
|
@ -50,7 +50,26 @@ def test_config_from_dot_env(tmp_path, monkeypatch) -> None:
|
|||
assert config.local.enabled is True
|
||||
|
||||
|
||||
def test_config_sources_yaml(tmp_path, monkeypatch):
|
||||
def test_config_from_dot_env_override(tmp_path, monkeypatch) -> None:
|
||||
get_config.cache_clear()
|
||||
initial_config: Config = get_config()
|
||||
assert initial_config.client.enabled is False
|
||||
|
||||
env_content = """
|
||||
01_CLIENT_ENABLED=true
|
||||
"""
|
||||
p: Any = tmp_path / ".env"
|
||||
p.write_text(env_content)
|
||||
monkeypatch.chdir(tmp_path)
|
||||
load_dotenv(dotenv_path=str(p))
|
||||
|
||||
get_config.cache_clear()
|
||||
updated_config: Config = get_config()
|
||||
assert updated_config.client.enabled is True
|
||||
|
||||
|
||||
def test_config_sources_yaml(tmp_path, monkeypatch) -> None:
|
||||
get_config.cache_clear()
|
||||
yaml_content = """
|
||||
llm:
|
||||
model: test
|
||||
|
@ -58,11 +77,12 @@ def test_config_sources_yaml(tmp_path, monkeypatch):
|
|||
server:
|
||||
port: 8080
|
||||
"""
|
||||
p: Any = tmp_path / "config.yaml"
|
||||
p.write_text(yaml_content)
|
||||
monkeypatch.setenv("01_CONFIG_FILE", str(p))
|
||||
config_path: Any = tmp_path / "config.yaml"
|
||||
config_path.write_text(yaml_content)
|
||||
monkeypatch.chdir(tmp_path)
|
||||
|
||||
config = Config()
|
||||
get_config.cache_clear()
|
||||
config: Config = get_config()
|
||||
assert config.llm.model == "test"
|
||||
assert config.llm.temperature == 1.0
|
||||
assert config.server.port == 8080
|
||||
|
|
Loading…
Reference in New Issue