diff --git a/README.md b/README.md index c25c111..9d21ded 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ GPTAuthor is a tool for writing long form, multi-chapter stories and novels usin ## Installation -You can install gptauthor using pip: +You can install [gptauthor](https://pypi.org/project/gptauthor/) using pip: ```bash pip install gptauthor @@ -23,12 +23,12 @@ This example reads the story prompt from the example file [prompts-openai-drama. ```bash export OPENAI_API_KEY=sk- -gptauthor --story openai-drama --total-chapters 3 --llm-model gpt-3.5-turbo --llm-temperature 0.1 +gptauthor --story prompts-openai-drama --total-chapters 3 --llm-model gpt-3.5-turbo --llm-temperature 0.1 ``` ### Required Arguments -- `--story TEXT`: The name within the yaml file name defining the story [default: openai-drama] +- `--story TEXT`: The name of the yaml file defining the story and prompts ### Optional Arguments @@ -36,7 +36,7 @@ gptauthor --story openai-drama --total-chapters 3 --llm-model gpt-3.5-turbo --ll - `--llm-temperature FLOAT`: LLM temperature value (0 to 2, OpenAI default is 1) [default: 1] - `--llm-top-p FLOAT`: LLM top_p probability value (0 to 2, OpenAI default is 1) [default: 1] - `--llm-use-localhost INTEGER`: LLM use localhost:8081 instead of openai [default: 0] -- `--total-chapters INTEGER`: Total chapters to write [default: 5] +- `--total-chapters INTEGER`: Total chapters to write [default: 3] - `--allow-user-input / --no-allow-user-input`: Allow command line user input [default: allow-user-input] - `--version`: Display gptauthor version - `--install-completion`: Install completion for the current shell. diff --git a/gptauthor/console.py b/gptauthor/console.py index 6b8c1c3..f4137bf 100644 --- a/gptauthor/console.py +++ b/gptauthor/console.py @@ -15,12 +15,13 @@ def version_callback(value: bool): if value: print(f"{consts.package_name} version: {consts.version}") + print("Please visit https://github.com/dylanhogg/gptauthor for more info.") raise typer.Exit() @typer_app.command() def run( - story: Annotated[str, typer.Option(help="The name within the yaml file name defining the story")], + story: Annotated[str, typer.Option(help="The name of the yaml file defining the story and prompts")], llm_model: Annotated[str, typer.Option(help="The model name")] = consts.default_llm_model, llm_temperature: Annotated[ float, typer.Option(help="LLM temperature value (0 to 2, OpenAI default is 1)") @@ -44,7 +45,7 @@ def run( try: log.configure() - example_usage = f"Example usage: [bold green]{consts.package_name} --story openai-drama --total-chapters 3 --llm-model gpt-3.5-turbo --llm-temperature 0.1 --llm-top-p 1.0[/bold green]" + example_usage = f"Example usage: [bold green]{consts.package_name} --story prompts-openai-drama --total-chapters 3 --llm-model gpt-3.5-turbo --llm-temperature 0.1 --llm-top-p 1.0[/bold green]" llm_api_key = env.get("OPENAI_API_KEY", "") if not llm_use_localhost and not llm_api_key: @@ -54,7 +55,7 @@ def run( "\nAlternatively you can use the '--llm_use_localhost 1' argument to use a local LLM server." ) - story_file = f"prompts-{story}.yaml" + story_file = f"{story}.yaml" llm_config = OmegaConf.create( { "version": consts.version, @@ -84,7 +85,7 @@ def run( if ex.exit_code == 0: print() print( - "[bold green]Good bye and thanks for using gptauthor! Please visit https://github.com/dylanhogg/gptauthor for more info.[/bold green]" + "[bold green]Goodbye and thanks for using gptauthor! Please visit https://github.com/dylanhogg/gptauthor for more info.[/bold green]" ) return print(example_usage) diff --git a/gptauthor/library/consts.py b/gptauthor/library/consts.py index 028a52c..bbd22b1 100644 --- a/gptauthor/library/consts.py +++ b/gptauthor/library/consts.py @@ -4,7 +4,7 @@ version = pkg_resources.get_distribution(package_name).version default_output_folder = "./_output/" -default_write_total_chapters = 5 +default_write_total_chapters = 3 # https://platform.openai.com/docs/api-reference/chat/create default_llm_use_localhost = 0 diff --git a/gptauthor/library/engine.py b/gptauthor/library/engine.py index c27c158..40bde5d 100644 --- a/gptauthor/library/engine.py +++ b/gptauthor/library/engine.py @@ -45,6 +45,8 @@ def do_writing(llm_config): p( f"Start {consts.package_name} {consts.version}, {llm_config.total_chapters=}, {llm_config.story_file=}, {llm_config.allow_user_input=}..." ) + p(f"Full story prompt file path: {prompts.get_yaml_file(llm_config).resolve()}") + print() # ------------------------------------------------------------------------------ # Create synopsis @@ -256,3 +258,5 @@ def do_writing(llm_config): return else: print("Invalid input. Please try again.") + + return output_folder diff --git a/gptauthor/library/prompts.py b/gptauthor/library/prompts.py index c3e276a..8ac6e25 100644 --- a/gptauthor/library/prompts.py +++ b/gptauthor/library/prompts.py @@ -1,5 +1,7 @@ import importlib.resources +from pathlib import Path +from loguru import logger from omegaconf import DictConfig, OmegaConf from gptauthor.library import consts @@ -7,7 +9,7 @@ def _get_common(key: str, llm_config: DictConfig): - yaml_file = importlib.resources.files(consts.package_name).joinpath(llm_config.story_file) + yaml_file = get_yaml_file(llm_config) conf_file = OmegaConf.load(yaml_file) if key not in conf_file: raise Exception(f"{key} not in conf_file") @@ -15,7 +17,7 @@ def _get_common(key: str, llm_config: DictConfig): def _get_conf(prompt_type: str, llm_config) -> (str, dict): - yaml_file = importlib.resources.files(consts.package_name).joinpath(llm_config.story_file) + yaml_file = get_yaml_file(llm_config) conf_file = OmegaConf.load(yaml_file) if prompt_type not in conf_file: valid_prompt_types = sorted( @@ -28,6 +30,23 @@ def _get_conf(prompt_type: str, llm_config) -> (str, dict): return conf +def get_yaml_file(llm_config: DictConfig): + local_yaml_file = Path(llm_config.story_file) + if local_yaml_file.is_file(): + logger.info(f"Using local yaml file: {local_yaml_file}") + return local_yaml_file + + resources_yaml_file = Path(importlib.resources.files(consts.package_name).joinpath(llm_config.story_file)) + if resources_yaml_file.is_file(): + logger.info(f"Using resources yaml file: {resources_yaml_file}") + return resources_yaml_file + + raise Exception( + f"Could not find yaml file: {llm_config.story_file} either locally or in the resources folder. " + "See here for an example: https://github.com/dylanhogg/gptauthor/blob/main/gptauthor/prompts-openai-drama.yaml" + ) + + def get_prompt(prompt_type: str, llm_config: DictConfig): return _get_conf(prompt_type, llm_config).prompt diff --git a/gptauthor/library/utils.py b/gptauthor/library/utils.py index 3aa8290..3464832 100644 --- a/gptauthor/library/utils.py +++ b/gptauthor/library/utils.py @@ -47,7 +47,7 @@ def synopsis_processer(synopsis_response): return title, chapters -def get_folder(synopsis_title: str, synopsis_chapters: list[str], llm_config: dict): +def get_folder(synopsis_title: str, synopsis_chapters: list[str], llm_config: dict) -> Path: now = datetime.now() safe_title = _make_safe_filename(synopsis_title) num_chapters = len(synopsis_chapters) diff --git a/gptauthor/prompts-openai-drama.yaml b/gptauthor/prompts-openai-drama.yaml index 8584fbb..a75be9d 100644 --- a/gptauthor/prompts-openai-drama.yaml +++ b/gptauthor/prompts-openai-drama.yaml @@ -65,7 +65,7 @@ synopsis: The final chapter has a twist that is unexpected, but makes sense in hindsight. First, give the title of the book. - Then give each of the {total_chapters} chapters an outline, in the format "Chapter N: ", followed by 4 to 6 bullet points identifing the key chapter elements contributing to the overall story arc. Ensure that the story and chapters flow. + Then give each of the {total_chapters} chapters an outline, in the format "Chapter N: <title>", followed by 4 to 6 bullet points that describe key chapter elements contributing to the overall story arc. Ensure that the story and chapters flow. expand-chapter-first: system: You are a clever and creative story book author. You are skilled at weaving stories that are coherent, and fun to read. You are skilled at creating characters that are engaging and believable. diff --git a/pyproject.toml b/pyproject.toml index c4dda7d..37cec46 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "gptauthor" -version = "0.3.0" +version = "0.4.0" description = "GPTAuthor is a tool for writing long form stories using AI" authors = ["Dylan Hogg <dylanhogg@gmail.com>"] license = "MIT"