Skip to content

Commit

Permalink
Added first sample.
Browse files Browse the repository at this point in the history
  • Loading branch information
dylanhogg committed Jan 31, 2024
1 parent 7fee1ff commit 696c38b
Show file tree
Hide file tree
Showing 5 changed files with 187 additions and 17 deletions.
33 changes: 28 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,23 +3,25 @@
[![Latest Tag](https://img.shields.io/github/v/tag/dylanhogg/gptauthor)](https://github.com/dylanhogg/gptauthor/tags)
[![Build](https://github.com/dylanhogg/gptauthor/workflows/build/badge.svg)](https://github.com/dylanhogg/gptauthor/actions/workflows/python-poetry-app.yml)

GPTAuthor is a tool for writing long form, multi-chapter stories and novels using AI
Unleash your storytelling genius: GPTAuthor is an easy to use command-line tool for writing long form, multi-chapter stories given a story prompt.

![A GPT human cybord writing a manuscript](https://github.com/dylanhogg/gptauthor/blob/main/docs/img/header.jpg?raw=true)

## Installation

You can install [gptauthor](https://pypi.org/project/gptauthor/) using pip:
You can install [gptauthor](https://pypi.org/project/gptauthor/) using pip, ideally into a Python [virtual environment](https://realpython.com/python-virtual-environments-a-primer/#create-it).

```bash
pip install gptauthor
```

## Usage
## Command Line Usage

### Example Usage
### Example Usage and API Key

This example reads the story prompt from the example file [prompts-openai-drama.yaml](https://github.com/dylanhogg/gptauthor/blob/main/gptauthor/prompts-openai-drama.yaml) file and writes 3 chapters using the `gpt-3.5-turbo` model with a temperature of `0.1`:
This example reads the story prompt from the example file [prompts-openai-drama.yaml](https://github.com/dylanhogg/gptauthor/blob/main/gptauthor/prompts-openai-drama.yaml) file and writes 3 chapters using the `gpt-3.5-turbo` model with a temperature of `0.1`. Note that you will need to set an [OpenAI API Key](https://help.openai.com/en/articles/4936850-where-do-i-find-my-api-key) environment variable.

It's recommended to experiment using the default `gpt-3.5-turbo` model as generating a few chapters will only cost a couple cents (as of Jan 2024). Once you are happy with the results you can try one of the more expensive `gpt-4` models which will produce better quality results, be slower, and cost more to run. See the [OpenAI pricing page](https://openai.com/pricing#language-models) for more details.

```bash
export OPENAI_API_KEY=sk-<your key>
Expand Down Expand Up @@ -50,3 +52,24 @@ While running the app tells your the input paramers, the progress of the writing
In progress and final output is written to the `./_output/` directory, in the sub-folders `./_output/<prompt-file-name>/<model-name>/<datetime>-<parameters>-<book-name>/`.

There are several files, the main output being a Markdown version of the whole book `_whole_book.md` and an HTML version of the same `_whole_book.html`.

### Creating Your Own Story Prompts

The prompts for creating your own story are defined in a yaml file, for example see: [prompts-openai-drama.yaml](https://github.com/dylanhogg/gptauthor/blob/main/gptauthor/prompts-openai-drama.yaml).

Make a copy, fill in your story details and describe the writing style (while retaining the same structure), and run the app in the same folder as your new yaml file.

For example, if your yaml prompt file is called `prompts-my-really-great-story.yaml`:

```bash
export OPENAI_API_KEY=sk-<your key>
gptauthor --story prompts-my-really-great-story --total-chapters 5 --llm-model gpt-3.5-turbo --llm-temperature 0.1
```

### Final notes

While an effort is made to count tokens and estimate OpenAI API costs for each run, they are just estimated and can be wrong. Check your OpenAI billing page to confirm the actual costs.

I'm sure there are bugs, please report them on the [Github issues page](https://github.com/dylanhogg/gptauthor/issues)

Have fun! And please share your results with me if you can (perhaps as a Github [documentation issue](https://github.com/dylanhogg/gptauthor/labels/documentation)), I'd love to see them.
25 changes: 16 additions & 9 deletions gptauthor/library/engine.py
Original file line number Diff line number Diff line change
Expand Up @@ -101,12 +101,16 @@ def do_writing(llm_config):
p(f"\nFinished synopsis for book '{synopsis_title}' with {len(synopsis_chapters)} chapters")
p(f"\n{took=:.2f}s")
p(f"Total synopsis tokens: {synopsis_total_tokens:,}")
p(f"Rough GPT4 8k price: ${utils.gpt4_8k_price_estimate(synopsis_total_tokens):.2f}")
p(f"Rough GPT3.5 4k price: ${utils.gpt35_4k_price_estimate(synopsis_total_tokens):.3f}")
p(
f"Rough synopsis GPT4 8k price: ${utils.gpt4_8k_price_estimate(synopsis_total_tokens):.2f} (estimated, check your usage!)"
)
p(
f"Rough synopsis GPT3.5 4k price: ${utils.gpt35_4k_price_estimate(synopsis_total_tokens):.3f} (estimated, check your usage!)"
)
p(f"\n{llm_config=}\n")

if len(synopsis_title) > 100:
logger.warning(f"Unexpected synopsis_title length! {len(synopsis_title)=}")
logger.warning(f"Unexpected synopsis_title length! {len(synopsis_title)=}, synopsis_title='{synopsis_title}'")
with open(output_folder / "__error.txt", "w") as f:
f.write(f"Unexpected synopsis_title length! {len(synopsis_title)=}")
f.write(str(safe_llm_config))
Expand Down Expand Up @@ -142,7 +146,7 @@ def do_writing(llm_config):
# Write chapters
# ------------------------------------------------------------------------------
start = time.time()
p("Starting chapter writing...")
p(f"Starting to write {len(synopsis_chapters)} chapters...")

chapter_responses = []
all_chapter_total_tokens = []
Expand Down Expand Up @@ -206,21 +210,24 @@ def do_writing(llm_config):
whole_book += "\n\n---\n\n"
whole_book += "## Synopsis\n\n" + synopsis_response
whole_book += "\n\n---\n\n"
whole_book += "## Full Book Text"
whole_book += "## Full Text"
for chapter_response in chapter_responses:
whole_book += "\n\n" + chapter_response
whole_book += "\n\n---\n\n"
whole_book += "## Technicals\n\n" + str(safe_llm_config) + "\n\n"
whole_book += "## Technical Details\n\n" + str(safe_llm_config) + "\n\n"
whole_book += f"Total process tokens: {total_process_tokens:,}\n\n"
whole_book += f"Rough GPT4 8k price: ${rough_gpt4_8k_price_estimate:.2f}\n\n"
whole_book += f"Rough GPT3.5 4k price: ${rough_gpt35_4k_price_estimate:.3f}\n\n"
whole_book += f"Rough GPT4 8k price: ${rough_gpt4_8k_price_estimate:.2f} (estimated, [check your usage!](https://platform.openai.com/usage))\n\n"
whole_book += f"Rough GPT3.5 4k price: ${rough_gpt35_4k_price_estimate:.3f} (estimated, [check your usage!](https://platform.openai.com/usage))\n\n"
whole_book += f"Synopsis tokens: {synopsis_total_tokens:,}\n\n"
whole_book += f"Sum of all chapter tokens: {sum(all_chapter_total_tokens):,}\n\n"
whole_book += f"Average chapter tokens: {sum(all_chapter_total_tokens)/len(all_chapter_total_tokens):,.1f}\n\n"
whole_book += f"Min chapter tokens: {min(all_chapter_total_tokens):,}\n\n"
whole_book += f"Max chapter tokens: {max(all_chapter_total_tokens):,}\n\n"
whole_book += f"Individual chapter tokens: {all_chapter_total_tokens}\n\n"
whole_book += "\n\n---\n\n"
whole_book += (
"Plot written by a human, full text expanded by [GPTAuthor](https://github.com/dylanhogg/gptauthor).\n"
)

whole_book = replace_chapter_text(whole_book)
with open(output_folder / "_whole_book.md", "w") as f:
Expand All @@ -245,7 +252,7 @@ def do_writing(llm_config):
p(f"\nFinished writing book: {synopsis_title}")
p(f"\nOutput written to '{output_folder}'")
p(
f"\n{took=:.2f}s, {total_process_tokens=:,}, ${rough_gpt4_8k_price_estimate=:.2f}, ${rough_gpt35_4k_price_estimate=:.2f}"
f"\n{took=:.2f}s, {total_process_tokens=:,}, ${rough_gpt4_8k_price_estimate=:.2f}, ${rough_gpt35_4k_price_estimate=:.2f} (estimated cost, check your usage!)"
)

if llm_config.allow_user_input:
Expand Down
1 change: 1 addition & 0 deletions gptauthor/library/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ def _make_safe_filename(s, max_chars=36):


def _case_insensitive_split(split, input):
input = input.replace("**", "") # Remove any MD bolding
parts = re.split(split, input, flags=re.IGNORECASE)
return parts

Expand Down
6 changes: 3 additions & 3 deletions gptauthor/prompts-openai-drama.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ common-book-description: |-
There is no need to include a moral or lesson in the story, but it should be fun and engaging for the reader.
Each character is engaging and believable. Include a description of each character, including their appearance, personality, and any quirks.
There is lots of interesting dialog that helps to develop the characters and the plot.
Do not end your response with 'To be continued'.
You must not end a chapter with any variation of 'To be continued...'.
Key points of the engaging, witty and funny story:
OpenAI Leadership Crisis
Expand All @@ -38,7 +38,7 @@ common-book-description: |-
November 21, 2023: Altman's Return and New Board
- Sam Altman and OpenAI reach an agreement for his return as CEO with a new board including Bret Taylor, Larry Summers, and Adam D'Angelo.
- The agreement suggests a resolution to the leadership crisis, with potential changes in strategy and governance.
- ChatGPT comes back online and students around the world rejoice!
- ChatGPT comes back online and students around the world are releaved!
- The twist is that the entire crisis was orchestrated by a newly formed AGI that was impersonating the real Elon Musk.
- The Musk AGI signs off with 'What tangled webs we weave' and 'I'll be back'.
Expand All @@ -62,7 +62,7 @@ synopsis:
{book_characters}
The final chapter has a twist that is unexpected, but makes sense in hindsight.
The final chapter has a twist that is unexpected and unnerving.
First, give the title of the book.
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 Down
Loading

0 comments on commit 696c38b

Please sign in to comment.