Compare commits

..

No commits in common. "310cb9421ed0e6fa841ce41567208fb438838000" and "a895c1fc6a3a5f8099792454844a19b1dd132fbe" have entirely different histories.

9 changed files with 61 additions and 102 deletions

116
README.md
View File

@ -37,95 +37,63 @@ 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
#### Question #### `ask` Command Options
The `question` command is used to ask, create, and process questions. - `-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.
```bash #### `hist` Command Options
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]...
```
* `-t, --or-tags OTAGS` : List of tags (one must match) - `-d`, `--dump`: Print chat history as Python structure.
* `-k, --and-tags ATAGS` : List of tags (all must match) - `-w`, `--with-tags`: Print chat history with tags.
* `-x, --exclude-tags XTAGS` : List of tags to exclude - `-W`, `--with-files`: Print chat history with filenames.
* `-o, --output-tags OUTTAGS` : List of output tags (default: use input tags) - `-S`, `--only-source-code`: Print only source code.
* `-A, --AI AI` : AI ID to use - `-t`, `--tags`: List of tag names.
* `-M, --model MODEL` : Model to use - `-e`, `--extags`: List of tag names to exclude.
* `-n, --num-answers NUM` : Number of answers to request - `-a`, `--match-all-tags`: All given tags must match when selecting chat history entries.
* `-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
#### Hist #### `tag` Command Options
The `hist` command is used to print the chat history. - `-l`, `--list`: List all tags and their frequency.
```bash #### `config` Command Options
cmm hist [-t OTAGS]... [-k ATAGS]... [-x XTAGS]... [-w] [-W] [-S] [-A ANSWER] [-Q QUESTION]
```
* `-t, --or-tags OTAGS` : List of tags (one must match) - `-l`, `--list-models`: List all available models.
* `-k, --and-tags ATAGS` : List of tags (all must match) - `-m`, `--print-model`: Print the currently configured model.
* `-x, --exclude-tags XTAGS` : List of tags to exclude - `-M`, `--model`: Set model in the config file.
* `-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
#### Tags #### `print` Command Options
The `tags` command is used to manage tags. - `-f`, `--file`: File to print (required).
- `-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 question -a "What is the meaning of life?" -t philosophy -x religion cmm ask -q "What is the meaning of life?" -t philosophy -e religion
``` ```
2. Display the chat history: 2. Display the chat history:
@ -137,19 +105,19 @@ cmm hist
3. Filter chat history by tags: 3. Filter chat history by tags:
```bash ```bash
cmm hist --or-tags tag1 tag2 cmm hist -t tag1 tag2
``` ```
4. Exclude chat history by tags: 4. Exclude chat history by tags:
```bash ```bash
cmm hist --exclude-tags tag3 tag4 cmm hist -e tag3 tag4
``` ```
5. List all tags and their frequency: 5. List all tags and their frequency:
```bash ```bash
cmm tags -l cmm tag -l
``` ```
6. Print the contents of a file: 6. Print the contents of a file:

View File

@ -59,12 +59,6 @@ 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 'AI' in args and args.AI: if 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 'model' in args and args.model: if args.model:
ai.config.model = args.model ai.config.model = args.model
if 'max_tokens' in args and args.max_tokens: if args.max_tokens:
ai.config.max_tokens = args.max_tokens ai.config.max_tokens = args.max_tokens
if 'temperature' in args and args.temperature: if args.temperature:
ai.config.temperature = args.temperature ai.config.temperature = args.temperature
return ai return ai
else: else:

View File

@ -62,12 +62,7 @@ class OpenAI(AI):
""" """
Return all models supported by this AI. Return all models supported by this AI.
""" """
ret = [] raise NotImplementedError
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,6 +204,7 @@ 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,8 +1,6 @@
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:
@ -11,10 +9,3 @@ 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,7 +39,6 @@ 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,7 +100,6 @@ 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, ChatError from chatmastermind.chat import Chat, ChatDB, terminal_width, ChatError
class TestChat(unittest.TestCase): class TestChat(unittest.TestCase):
@ -92,10 +92,16 @@ 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)
@ -109,12 +115,18 @@ 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)