diff --git a/README.md b/README.md index 1e16e95..449a978 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,49 @@ # LLM Chat -A general CLI interface for large language models. +This project is currently a CLI interface for OpenAI's [GPT model API](https://platform.openai.com/docs/guides/gpt). The long term goal is to be much more general and interface with any LLM, whether that be a cloud service or a model running locally. + +## Usage + +### Installation + +The package is not currently published so you will need to build it yourself. To do so you will need [Poetry](https://python-poetry.org/) v1.5 or later. Once you have that installed, run the following commands: + +```bash +git clone https://code.harrison.sh/paul/llm-chat.git +cd llm-chat +poetry build +``` + +This will create a wheel file in the `dist` directory. You can then install it with `pip`: + +```bash +pip install dist/llm_chat-0.6.1-py3-none-any.whl +``` + +Note, a much better way to install this package system wide is to use [pipx](https://pypa.github.io/pipx/). This will install the package in an isolated environment and make the `llm` command available on your path. + +### Configuration + +Your OpenAI API key must be set in the `OPENAI_API_KEY` environment variable. The following additional environment variables are supported: + +| Variable | Description | +| -------------------- | ------------------------------------------------------------------ | +| `OPENAI_MODEL` | The model to use. Defaults to `gpt-3.5-turbo`. | +| `OPENAI_TEMPERATURE` | The temperature to use when generating text. Defaults to `0.7`. | +| `OPENAI_HISTORY_DIR` | The directory to store chat history in. Defaults to `~/.llm_chat`. | + +The settings can also be configured via command line arguments. Run `llm chat --help` for more information. + +### Usage + +To start a chat session, run the following command: + +```bash +llm chat +``` + +This will start a chat session with the default settings looking something like the image below: + +![Chat session](./llm-chat.png) + +The CLI accepts multi-line input, so to send the input to the model press `Esc + Enter`. After each message a running total cost will be displayed. To exit the chat session, send the message `/q`. diff --git a/llm-chat.png b/llm-chat.png new file mode 100644 index 0000000..4ae6b7f Binary files /dev/null and b/llm-chat.png differ diff --git a/pyproject.toml b/pyproject.toml index 2455a40..2265524 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "llm-chat" -version = "0.6.0" +version = "0.6.1" description = "A general CLI interface for large language models." authors = ["Paul Harrison "] readme = "README.md" diff --git a/src/llm_chat/settings.py b/src/llm_chat/settings.py index 783c850..dd54961 100644 --- a/src/llm_chat/settings.py +++ b/src/llm_chat/settings.py @@ -1,6 +1,7 @@ from enum import StrEnum from pathlib import Path +from pydantic import field_validator from pydantic_settings import BaseSettings, SettingsConfigDict @@ -13,7 +14,7 @@ class Model(StrEnum): DEFAULT_MODEL = Model.GPT3 DEFAULT_TEMPERATURE = 0.7 -DEFAULT_HISTORY_DIR = Path().absolute() / ".history" +DEFAULT_HISTORY_DIR = Path.home() / ".llm_chat" class OpenAISettings(BaseSettings): @@ -31,3 +32,10 @@ class OpenAISettings(BaseSettings): frozen=True, use_enum_values=True, ) + + @field_validator("history_dir") + def history_dir_must_exist(cls, history_dir: Path) -> Path: + """Ensure that the history directory exists.""" + if not history_dir.exists(): + history_dir.mkdir(parents=True) + return history_dir diff --git a/tests/conftest.py b/tests/conftest.py index b3bfafb..b315825 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,4 +1,5 @@ import os +from pathlib import Path import pytest @@ -7,3 +8,9 @@ import pytest def mock_openai_api_key() -> None: """Set a fake OpenAI API key.""" os.environ["OPENAI_API_KEY"] = "dummy_key" + + +@pytest.fixture(autouse=True) +def mock_history_dir(tmp_path: Path) -> None: + """Set a fake history directory.""" + os.environ["OPENAI_HISTORY_DIR"] = str(tmp_path / ".llm_chat")