From 2b62cb8c4be08b541cf8eee71ca7c731af7100b5 Mon Sep 17 00:00:00 2001 From: Oleksandr Kozachuk Date: Sat, 9 Sep 2023 19:24:45 +0200 Subject: [PATCH 1/4] Remove the `-*terminal_width()` to save space on screen. --- chatmastermind/chat.py | 1 - tests/test_chat.py | 14 +------------- 2 files changed, 1 insertion(+), 14 deletions(-) diff --git a/chatmastermind/chat.py b/chatmastermind/chat.py index 7c4dd35..dd18293 100644 --- a/chatmastermind/chat.py +++ b/chatmastermind/chat.py @@ -204,7 +204,6 @@ class Chat: output.append(message.to_str(source_code_only=True)) continue output.append(message.to_str(with_tags, with_files)) - output.append('\n' + ('-' * terminal_width()) + '\n') if paged: print_paged('\n'.join(output)) else: diff --git a/tests/test_chat.py b/tests/test_chat.py index 1916a2b..f34cb24 100644 --- a/tests/test_chat.py +++ b/tests/test_chat.py @@ -6,7 +6,7 @@ from io import StringIO from unittest.mock import patch from chatmastermind.tags import TagLine from chatmastermind.message import Message, Question, Answer, Tag, MessageFilter -from chatmastermind.chat import Chat, ChatDB, terminal_width, ChatError +from chatmastermind.chat import Chat, ChatDB, ChatError class TestChat(unittest.TestCase): @@ -92,16 +92,10 @@ class TestChat(unittest.TestCase): Question 1 {Answer.txt_header} Answer 1 - -{'-'*terminal_width()} - {Question.txt_header} Question 2 {Answer.txt_header} Answer 2 - -{'-'*terminal_width()} - """ self.assertEqual(mock_stdout.getvalue(), expected_output) @@ -115,18 +109,12 @@ FILE: 0001.txt Question 1 {Answer.txt_header} Answer 1 - -{'-'*terminal_width()} - {TagLine.prefix} btag2 FILE: 0002.txt {Question.txt_header} Question 2 {Answer.txt_header} Answer 2 - -{'-'*terminal_width()} - """ self.assertEqual(mock_stdout.getvalue(), expected_output) -- 2.36.6 From f96e82bdd7c96fe12de38956be501b715c4d6a9c Mon Sep 17 00:00:00 2001 From: Oleksandr Kozachuk Date: Tue, 12 Sep 2023 16:34:17 +0200 Subject: [PATCH 2/4] Implement the config -l and config -m commands. --- chatmastermind/ai.py | 6 ++++++ chatmastermind/commands/config.py | 9 +++++++++ chatmastermind/configuration.py | 1 + 3 files changed, 16 insertions(+) diff --git a/chatmastermind/ai.py b/chatmastermind/ai.py index b97b5f1..622aa4f 100644 --- a/chatmastermind/ai.py +++ b/chatmastermind/ai.py @@ -59,6 +59,12 @@ class AI(Protocol): """ raise NotImplementedError + def print_models(self) -> None: + """ + Print all models supported by this AI. + """ + raise NotImplementedError + def tokens(self, data: Union[Message, Chat]) -> int: """ Computes the nr. of AI language tokens for the given message diff --git a/chatmastermind/commands/config.py b/chatmastermind/commands/config.py index 262164c..3714573 100644 --- a/chatmastermind/commands/config.py +++ b/chatmastermind/commands/config.py @@ -1,6 +1,8 @@ import argparse from pathlib import Path from ..configuration import Config +from ..ai import AI +from ..ai_factory import create_ai def config_cmd(args: argparse.Namespace) -> None: @@ -9,3 +11,10 @@ def config_cmd(args: argparse.Namespace) -> None: """ if args.create: Config.create_default(Path(args.create)) + elif args.list_models or args.print_model: + config: Config = Config.from_file(args.config) + ai: AI = create_ai(args, config) + if args.list_models: + ai.print_models() + else: + print(ai.config.model) diff --git a/chatmastermind/configuration.py b/chatmastermind/configuration.py index 5397f4a..1415eb2 100644 --- a/chatmastermind/configuration.py +++ b/chatmastermind/configuration.py @@ -39,6 +39,7 @@ class AIConfig: name: ClassVar[str] # a user-defined ID for an AI configuration entry ID: str + model: str = 'n/a' # the name must not be changed def __setattr__(self, name: str, value: Any) -> None: -- 2.36.6 From 544bf0bf069973a5b65e1e537a8863a36a66a7e5 Mon Sep 17 00:00:00 2001 From: Oleksandr Kozachuk Date: Tue, 12 Sep 2023 16:34:39 +0200 Subject: [PATCH 3/4] Improve README.md --- README.md | 116 ++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 74 insertions(+), 42 deletions(-) diff --git a/README.md b/README.md index d55102a..00f4720 100644 --- a/README.md +++ b/README.md @@ -37,63 +37,95 @@ cmm [global options] command [command options] ### Global Options -- `-c`, `--config`: Config file name (defaults to `.config.yaml`). - -### Commands - -- `ask`: Ask a question. -- `hist`: Print chat history. -- `tag`: Manage tags. -- `config`: Manage configuration. -- `print`: Print files. +- `-C`, `--config`: Config file name (defaults to `.config.yaml`). ### Command Options -#### `ask` Command Options +#### Question -- `-q`, `--question`: Question to ask (required). -- `-m`, `--max-tokens`: Max tokens to use. -- `-T`, `--temperature`: Temperature to use. -- `-M`, `--model`: Model to use. -- `-n`, `--number`: Number of answers to produce (default is 3). -- `-s`, `--source`: Add content of a file to the query. -- `-S`, `--only-source-code`: Add pure source code to the chat history. -- `-t`, `--tags`: List of tag names. -- `-e`, `--extags`: List of tag names to exclude. -- `-o`, `--output-tags`: List of output tag names (default is the input tags). -- `-a`, `--match-all-tags`: All given tags must match when selecting chat history entries. +The `question` command is used to ask, create, and process questions. -#### `hist` Command Options +```bash +cmm question [-t OTAGS]... [-k ATAGS]... [-x XTAGS]... [-o OUTTAGS]... [-A AI] [-M MODEL] [-n NUM] [-m MAX] [-T TEMP] (-a ASK | -c CREATE | -r REPEAT | -p PROCESS) [-O] [-s SOURCE]... [-S SOURCE]... +``` -- `-d`, `--dump`: Print chat history as Python structure. -- `-w`, `--with-tags`: Print chat history with tags. -- `-W`, `--with-files`: Print chat history with filenames. -- `-S`, `--only-source-code`: Print only source code. -- `-t`, `--tags`: List of tag names. -- `-e`, `--extags`: List of tag names to exclude. -- `-a`, `--match-all-tags`: All given tags must match when selecting chat history entries. +* `-t, --or-tags OTAGS` : List of tags (one must match) +* `-k, --and-tags ATAGS` : List of tags (all must match) +* `-x, --exclude-tags XTAGS` : List of tags to exclude +* `-o, --output-tags OUTTAGS` : List of output tags (default: use input tags) +* `-A, --AI AI` : AI ID to use +* `-M, --model MODEL` : Model to use +* `-n, --num-answers NUM` : Number of answers to request +* `-m, --max-tokens MAX` : Max. number of tokens +* `-T, --temperature TEMP` : Temperature value +* `-a, --ask ASK` : Ask a question +* `-c, --create CREATE` : Create a question +* `-r, --repeat REPEAT` : Repeat a question +* `-p, --process PROCESS` : Process existing questions +* `-O, --overwrite` : Overwrite existing messages when repeating them +* `-s, --source-text SOURCE` : Add content of a file to the query +* `-S, --source-code SOURCE` : Add source code file content to the chat history -#### `tag` Command Options +#### Hist -- `-l`, `--list`: List all tags and their frequency. +The `hist` command is used to print the chat history. -#### `config` Command Options +```bash +cmm hist [-t OTAGS]... [-k ATAGS]... [-x XTAGS]... [-w] [-W] [-S] [-A ANSWER] [-Q QUESTION] +``` -- `-l`, `--list-models`: List all available models. -- `-m`, `--print-model`: Print the currently configured model. -- `-M`, `--model`: Set model in the config file. +* `-t, --or-tags OTAGS` : List of tags (one must match) +* `-k, --and-tags ATAGS` : List of tags (all must match) +* `-x, --exclude-tags XTAGS` : List of tags to exclude +* `-w, --with-tags` : Print chat history with tags +* `-W, --with-files` : Print chat history with filenames +* `-S, --source-code-only` : Print only source code +* `-A, --answer ANSWER` : Search for answer substring +* `-Q, --question QUESTION` : Search for question substring -#### `print` Command Options +#### Tags -- `-f`, `--file`: File to print (required). -- `-S`, `--only-source-code`: Print only source code. +The `tags` command is used to manage tags. + +```bash +cmm tags (-l | -p PREFIX | -c CONTENT) +``` + +* `-l, --list` : List all tags and their frequency +* `-p, --prefix PREFIX` : Filter tags by prefix +* `-c, --contain CONTENT` : Filter tags by contained substring + +#### Config + +The `config` command is used to manage the configuration. + +```bash +cmm config (-l | -m | -c CREATE) +``` + +* `-l, --list-models` : List all available models +* `-m, --print-model` : Print the currently configured model +* `-c, --create CREATE` : Create config with default settings in the given file + +#### Print + +The `print` command is used to print message files. + +```bash +cmm print -f FILE [-q | -a | -S] +``` + +* `-f, --file FILE` : File to print +* `-q, --question` : Print only question +* `-a, --answer` : Print only answer +* `-S, --only-source-code` : Print only source code ### Examples 1. Ask a question: ```bash -cmm ask -q "What is the meaning of life?" -t philosophy -e religion +cmm question -a "What is the meaning of life?" -t philosophy -x religion ``` 2. Display the chat history: @@ -105,19 +137,19 @@ cmm hist 3. Filter chat history by tags: ```bash -cmm hist -t tag1 tag2 +cmm hist --or-tags tag1 tag2 ``` 4. Exclude chat history by tags: ```bash -cmm hist -e tag3 tag4 +cmm hist --exclude-tags tag3 tag4 ``` 5. List all tags and their frequency: ```bash -cmm tag -l +cmm tags -l ``` 6. Print the contents of a file: -- 2.36.6 From 1ec3d6fcdaba199594dc847c6251e4c55d7e5e87 Mon Sep 17 00:00:00 2001 From: Oleksandr Kozachuk Date: Tue, 12 Sep 2023 16:37:50 +0200 Subject: [PATCH 4/4] Make it possible to specify the AI in config command. --- chatmastermind/ai_factory.py | 8 ++++---- chatmastermind/ais/openai.py | 7 ++++++- chatmastermind/main.py | 1 + 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/chatmastermind/ai_factory.py b/chatmastermind/ai_factory.py index 420b287..a3cf9c3 100644 --- a/chatmastermind/ai_factory.py +++ b/chatmastermind/ai_factory.py @@ -17,7 +17,7 @@ def create_ai(args: argparse.Namespace, config: Config) -> AI: # noqa: 11 is not found, it uses the first AI in the list. """ ai_conf: AIConfig - if args.AI: + if 'AI' in args and args.AI: try: ai_conf = config.ais[args.AI] except KeyError: @@ -32,11 +32,11 @@ def create_ai(args: argparse.Namespace, config: Config) -> AI: # noqa: 11 if ai_conf.name == 'openai': ai = OpenAI(cast(OpenAIConfig, ai_conf)) - if args.model: + if 'model' in args and args.model: ai.config.model = args.model - if args.max_tokens: + if 'max_tokens' in args and args.max_tokens: ai.config.max_tokens = args.max_tokens - if args.temperature: + if 'temperature' in args and args.temperature: ai.config.temperature = args.temperature return ai else: diff --git a/chatmastermind/ais/openai.py b/chatmastermind/ais/openai.py index a388a7a..0e7ad41 100644 --- a/chatmastermind/ais/openai.py +++ b/chatmastermind/ais/openai.py @@ -62,7 +62,12 @@ class OpenAI(AI): """ Return all models supported by this AI. """ - raise NotImplementedError + ret = [] + for engine in sorted(openai.Engine.list()['data'], key=lambda x: x['id']): + if engine['ready']: + ret.append(engine['id']) + ret.sort() + return ret def print_models(self) -> None: """ diff --git a/chatmastermind/main.py b/chatmastermind/main.py index 99aca09..7e18185 100755 --- a/chatmastermind/main.py +++ b/chatmastermind/main.py @@ -100,6 +100,7 @@ def create_parser() -> argparse.ArgumentParser: help="Manage configuration", aliases=['c']) config_cmd_parser.set_defaults(func=config_cmd) + config_cmd_parser.add_argument('-A', '--AI', help='AI ID to use') config_group = config_cmd_parser.add_mutually_exclusive_group(required=True) config_group.add_argument('-l', '--list-models', help="List all available models", action='store_true') -- 2.36.6