Compare commits
5 Commits
a895c1fc6a
...
310cb9421e
| Author | SHA1 | Date | |
|---|---|---|---|
| 310cb9421e | |||
|
|
1ec3d6fcda | ||
|
|
544bf0bf06 | ||
|
|
f96e82bdd7 | ||
|
|
2b62cb8c4b |
116
README.md
116
README.md
@ -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:
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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:
|
||||||
|
|||||||
@ -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:
|
||||||
"""
|
"""
|
||||||
|
|||||||
@ -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:
|
||||||
|
|||||||
@ -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)
|
||||||
|
|||||||
@ -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:
|
||||||
|
|||||||
@ -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')
|
||||||
|
|||||||
@ -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)
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user