Merge pull request 'Cleanup after merge of restructurings #8' (#10) from cleanup into main

Reviewed-on: #10
This commit is contained in:
juk0de 2023-09-12 20:23:08 +02:00
commit 310cb9421e
9 changed files with 102 additions and 61 deletions

116
README.md
View File

@ -37,63 +37,95 @@ cmm [global options] command [command options]
### Global Options ### Global Options
- `-c`, `--config`: Config file name (defaults to `.config.yaml`). - `-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.
### Command Options ### Command Options
#### `ask` Command Options #### Question
- `-q`, `--question`: Question to ask (required). The `question` command is used to ask, create, and process questions.
- `-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.
#### `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. * `-t, --or-tags OTAGS` : List of tags (one must match)
- `-w`, `--with-tags`: Print chat history with tags. * `-k, --and-tags ATAGS` : List of tags (all must match)
- `-W`, `--with-files`: Print chat history with filenames. * `-x, --exclude-tags XTAGS` : List of tags to exclude
- `-S`, `--only-source-code`: Print only source code. * `-o, --output-tags OUTTAGS` : List of output tags (default: use input tags)
- `-t`, `--tags`: List of tag names. * `-A, --AI AI` : AI ID to use
- `-e`, `--extags`: List of tag names to exclude. * `-M, --model MODEL` : Model to use
- `-a`, `--match-all-tags`: All given tags must match when selecting chat history entries. * `-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. * `-t, --or-tags OTAGS` : List of tags (one must match)
- `-m`, `--print-model`: Print the currently configured model. * `-k, --and-tags ATAGS` : List of tags (all must match)
- `-M`, `--model`: Set model in the config file. * `-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). The `tags` command is used to manage tags.
- `-S`, `--only-source-code`: Print only source code.
```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 ### Examples
1. Ask a question: 1. Ask a question:
```bash ```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: 2. Display the chat history:
@ -105,19 +137,19 @@ cmm hist
3. Filter chat history by tags: 3. Filter chat history by tags:
```bash ```bash
cmm hist -t tag1 tag2 cmm hist --or-tags tag1 tag2
``` ```
4. Exclude chat history by tags: 4. Exclude chat history by tags:
```bash ```bash
cmm hist -e tag3 tag4 cmm hist --exclude-tags tag3 tag4
``` ```
5. List all tags and their frequency: 5. List all tags and their frequency:
```bash ```bash
cmm tag -l cmm tags -l
``` ```
6. Print the contents of a file: 6. Print the contents of a file:

View File

@ -59,6 +59,12 @@ class AI(Protocol):
""" """
raise NotImplementedError raise NotImplementedError
def print_models(self) -> None:
"""
Print all models supported by this AI.
"""
raise NotImplementedError
def tokens(self, data: Union[Message, Chat]) -> int: def tokens(self, data: Union[Message, Chat]) -> int:
""" """
Computes the nr. of AI language tokens for the given message Computes the nr. of AI language tokens for the given message

View File

@ -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. is not found, it uses the first AI in the list.
""" """
ai_conf: AIConfig ai_conf: AIConfig
if args.AI: if 'AI' in args and args.AI:
try: try:
ai_conf = config.ais[args.AI] ai_conf = config.ais[args.AI]
except KeyError: except KeyError:
@ -32,11 +32,11 @@ def create_ai(args: argparse.Namespace, config: Config) -> AI: # noqa: 11
if ai_conf.name == 'openai': if ai_conf.name == 'openai':
ai = OpenAI(cast(OpenAIConfig, ai_conf)) ai = OpenAI(cast(OpenAIConfig, ai_conf))
if args.model: if 'model' in args and args.model:
ai.config.model = 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 ai.config.max_tokens = args.max_tokens
if args.temperature: if 'temperature' in args and args.temperature:
ai.config.temperature = args.temperature ai.config.temperature = args.temperature
return ai return ai
else: else:

View File

@ -62,7 +62,12 @@ class OpenAI(AI):
""" """
Return all models supported by this 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: def print_models(self) -> None:
""" """

View File

@ -204,7 +204,6 @@ class Chat:
output.append(message.to_str(source_code_only=True)) output.append(message.to_str(source_code_only=True))
continue continue
output.append(message.to_str(with_tags, with_files)) output.append(message.to_str(with_tags, with_files))
output.append('\n' + ('-' * terminal_width()) + '\n')
if paged: if paged:
print_paged('\n'.join(output)) print_paged('\n'.join(output))
else: else:

View File

@ -1,6 +1,8 @@
import argparse import argparse
from pathlib import Path from pathlib import Path
from ..configuration import Config from ..configuration import Config
from ..ai import AI
from ..ai_factory import create_ai
def config_cmd(args: argparse.Namespace) -> None: def config_cmd(args: argparse.Namespace) -> None:
@ -9,3 +11,10 @@ def config_cmd(args: argparse.Namespace) -> None:
""" """
if args.create: if args.create:
Config.create_default(Path(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)

View File

@ -39,6 +39,7 @@ class AIConfig:
name: ClassVar[str] name: ClassVar[str]
# a user-defined ID for an AI configuration entry # a user-defined ID for an AI configuration entry
ID: str ID: str
model: str = 'n/a'
# the name must not be changed # the name must not be changed
def __setattr__(self, name: str, value: Any) -> None: def __setattr__(self, name: str, value: Any) -> None:

View File

@ -100,6 +100,7 @@ def create_parser() -> argparse.ArgumentParser:
help="Manage configuration", help="Manage configuration",
aliases=['c']) aliases=['c'])
config_cmd_parser.set_defaults(func=config_cmd) 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 = config_cmd_parser.add_mutually_exclusive_group(required=True)
config_group.add_argument('-l', '--list-models', help="List all available models", config_group.add_argument('-l', '--list-models', help="List all available models",
action='store_true') action='store_true')

View File

@ -6,7 +6,7 @@ from io import StringIO
from unittest.mock import patch from unittest.mock import patch
from chatmastermind.tags import TagLine from chatmastermind.tags import TagLine
from chatmastermind.message import Message, Question, Answer, Tag, MessageFilter 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): class TestChat(unittest.TestCase):
@ -92,16 +92,10 @@ class TestChat(unittest.TestCase):
Question 1 Question 1
{Answer.txt_header} {Answer.txt_header}
Answer 1 Answer 1
{'-'*terminal_width()}
{Question.txt_header} {Question.txt_header}
Question 2 Question 2
{Answer.txt_header} {Answer.txt_header}
Answer 2 Answer 2
{'-'*terminal_width()}
""" """
self.assertEqual(mock_stdout.getvalue(), expected_output) self.assertEqual(mock_stdout.getvalue(), expected_output)
@ -115,18 +109,12 @@ FILE: 0001.txt
Question 1 Question 1
{Answer.txt_header} {Answer.txt_header}
Answer 1 Answer 1
{'-'*terminal_width()}
{TagLine.prefix} btag2 {TagLine.prefix} btag2
FILE: 0002.txt FILE: 0002.txt
{Question.txt_header} {Question.txt_header}
Question 2 Question 2
{Answer.txt_header} {Answer.txt_header}
Answer 2 Answer 2
{'-'*terminal_width()}
""" """
self.assertEqual(mock_stdout.getvalue(), expected_output) self.assertEqual(mock_stdout.getvalue(), expected_output)