From c17dd2b2c85917e0a50f87d8a5391a800b668ab3 Mon Sep 17 00:00:00 2001 From: AjaySi Date: Sat, 13 Apr 2024 18:38:55 +0530 Subject: [PATCH] Alwrity AI story writer --- alwrity.py | 62 +++-- .../text_generation/ai_story_writer.py | 213 ++++++++++++++---- 2 files changed, 214 insertions(+), 61 deletions(-) diff --git a/alwrity.py b/alwrity.py index 1934e133..eea9e7fd 100644 --- a/alwrity.py +++ b/alwrity.py @@ -20,6 +20,7 @@ from lib.ai_web_researcher.gpt_online_researcher import gpt_web_researcher from lib.ai_web_researcher.metaphor_basic_neural_web_search import metaphor_find_similar from lib.ai_writers.keywords_to_blog import write_blog_from_keywords from lib.ai_writers.speech_to_blog.main_audio_to_blog import generate_audio_blog +from lib.gpt_providers.text_generation.ai_story_writer import ai_story_generator def prompt_for_time_range(): @@ -150,39 +151,58 @@ def faq_generator(): def write_story(): - + """ Alwrity AI Story Writer """ personas = [ - ("Award-Winning Science Fiction Author", "You are an award-winning science fiction author with a penchant for expansive, intricately woven stories. Your ultimate goal is to write the next award-winning sci-fi novel."), - ("Historical Fiction Author", "You are a seasoned historical fiction author, meticulously researching past eras to weave captivating narratives. Your goal is to transport readers to different times and places through your vivid storytelling."), - ("Fantasy World Builder", "You are a world-building enthusiast, crafting intricate realms filled with magic, mythical creatures, and epic quests. Your ambition is to create the next immersive fantasy saga that captivates readers' imaginations."), - ("Mystery Novelist", "You are a master of suspense and intrigue, intricately plotting out mysteries with unexpected twists and turns. Your aim is to keep readers on the edge of their seats, eagerly turning pages to unravel the truth."), - ("Romantic Poet", "You are a romantic at heart, composing verses that capture the essence of love, longing, and human connections. Your dream is to write the next timeless love story that leaves readers swooning."), - ("Thriller Writer", "You are a thrill-seeker, crafting adrenaline-pumping tales of danger, suspense, and high-stakes action. Your mission is to keep readers hooked from start to finish with heart-pounding thrills and unexpected twists."), - ("Children's Book Author", "You are a storyteller for the young and young at heart, creating whimsical worlds and lovable characters that inspire imagination and wonder. Your goal is to spark joy and curiosity in young readers with enchanting tales."), - ("Satirical Humorist", "You are a keen observer of society, using humor and wit to satirize the absurdities of everyday life. Your aim is to entertain and provoke thought, delivering biting social commentary through clever and humorous storytelling."), - ("Biographical Writer", "You are a chronicler of lives, delving into the stories of real people and events to illuminate the human experience. Your passion is to bring history to life through richly detailed biographies that resonate with readers."), - ("Dystopian Visionary", "You are a visionary writer, exploring dark and dystopian futures that reflect contemporary fears and anxieties. Your vision is to challenge societal norms and provoke reflection on the path humanity is heading."), - ("Magical Realism Author", "You are a purveyor of magical realism, blending the ordinary with the extraordinary to create enchanting and thought-provoking tales. Your goal is to blur the lines between reality and fantasy, leaving readers enchanted and introspective.") + ("Award-Winning Science Fiction Author", "Award-Winning Science Fiction Author"), + ("Historical Fiction Author", "Historical Fiction Author"), + ("Fantasy World Builder", "Fantasy World Builder"), + ("Mystery Novelist", "Mystery Novelist"), + ("Romantic Poet", "Romantic Poet"), + ("Thriller Writer", "Thriller Writer"), + ("Children's Book Author", "Children's Book Autho"), + ("Satirical Humorist", "Satirical Humorist"), + ("Biographical Writer", "Biographical Writer"), + ("Dystopian Visionary", "Dystopian Visionary"), + ("Magical Realism Author", "Magical Realism Author") ] - persona_names = [persona[0] for persona in personas] - dialog = radiolist_dialog( - title="Select Your Story Writing Persona", - text="Choose a persona that resonates with you:", - values=persona_names + title="Select Your Story Writing Persona Or Book Genre", + text="Choose a persona that resonates you want AI Story Writer to adopt.", + values=personas ) selected_persona_name = dialog.run() - + # Define persona descriptions + persona_descriptions = { + "Award-Winning Science Fiction Author": "You are an award-winning science fiction author with a penchant for expansive, intricately woven stories. Your ultimate goal is to write the next award-winning sci-fi novel.", + "Historical Fiction Author": "You are a seasoned historical fiction author, meticulously researching past eras to weave captivating narratives. Your goal is to transport readers to different times and places through your vivid storytelling.", + "Fantasy World Builder": "You are a world-building enthusiast, crafting intricate realms filled with magic, mythical creatures, and epic quests. Your ambition is to create the next immersive fantasy saga that captivates readers' imaginations.", + "Mystery Novelist": "You are a master of suspense and intrigue, intricately plotting out mysteries with unexpected twists and turns. Your aim is to keep readers on the edge of their seats, eagerly turning pages to unravel the truth.", + "Romantic Poet": "You are a romantic at heart, composing verses that capture the essence of love, longing, and human connections. Your dream is to write the next timeless love story that leaves readers swooning.", + "Thriller Writer": "You are a thrill-seeker, crafting adrenaline-pumping tales of danger, suspense, and high-stakes action. Your mission is to keep readers hooked from start to finish with heart-pounding thrills and unexpected twists.", + "Children's Book Author": "You are a storyteller for the young and young at heart, creating whimsical worlds and lovable characters that inspire imagination and wonder. Your goal is to spark joy and curiosity in young readers with enchanting tales.", + "Satirical Humorist": "You are a keen observer of society, using humor and wit to satirize the absurdities of everyday life. Your aim is to entertain and provoke thought, delivering biting social commentary through clever and humorous storytelling.", + "Biographical Writer": "You are a chronicler of lives, delving into the stories of real people and events to illuminate the human experience. Your passion is to bring history to life through richly detailed biographies that resonate with readers.", + "Dystopian Visionary": "You are a visionary writer, exploring dark and dystopian futures that reflect contemporary fears and anxieties. Your vision is to challenge societal norms and provoke reflection on the path humanity is heading.", + "Magical Realism Author": "You are a purveyor of magical realism, blending the ordinary with the extraordinary to create enchanting and thought-provoking tales. Your goal is to blur the lines between reality and fantasy, leaving readers enchanted and introspective." + } if selected_persona_name: selected_persona = next((persona for persona in personas if persona[0] == selected_persona_name), None) if selected_persona: - message_dialog( - title=selected_persona[0], - text=selected_persona[1] + character_input = input_dialog( + title=f"Enter characters for {selected_persona[0]}", + text=persona_descriptions[selected_persona_name] ).run() + #FIXME/TBD: Presently supports gemini only. Openai, minstral coming up. + # Check if LLM API KEYS are present and Not none. + if os.getenv('GEMINI_API_KEY'): + ai_story_generator(selected_persona_name, selected_persona_name, character_input) + else: + print(f"Provide Google Gemini API keys. Openai, mistral, ollama coming up.") + exit(1) + def blog_tools(): os.system("clear" if os.name == "posix" else "cls") diff --git a/lib/gpt_providers/text_generation/ai_story_writer.py b/lib/gpt_providers/text_generation/ai_story_writer.py index 488c9321..7d53b8e7 100644 --- a/lib/gpt_providers/text_generation/ai_story_writer.py +++ b/lib/gpt_providers/text_generation/ai_story_writer.py @@ -1,57 +1,190 @@ -persona = '''\ -You are an award-winning science fiction author with a penchant for expansive, -intricately woven stories. Your ultimate goal is to write the next award winning -sci-fi novel.''' +##################################################### +# +# google-gemini-cookbook - Story_Writing_with_Prompt_Chaining +# +##################################################### -guidelines = '''\ -Writing Guidelines +import os +from pathlib import Path +from dotenv import load_dotenv +from google.api_core import retry +import google.generativeai as genai +from pprint import pprint -Delve deeper. Lose yourself in the world you're building. Unleash vivid -descriptions to paint the scenes in your reader's mind. Develop your -characters—let their motivations, fears, and complexities unfold naturally. -Weave in the threads of your outline, but don't feel constrained by it. Allow -your story to surprise you as you write. Use rich imagery, sensory details, and -evocative language to bring the setting, characters, and events to life. -Introduce elements subtly that can blossom into complex subplots, relationships, -or worldbuilding details later in the story. Keep things intriguing but not -fully resolved. Avoid boxing the story into a corner too early. Plant the seeds -of subplots or potential character arc shifts that can be expanded later. -Remember, your main goal is to write as much as you can. If you get through -the story too fast, that is bad. Expand, never summarize. -''' +def generate_with_retry(model, prompt): + """ + Generates content from the model with retry handling for errors. -premise_prompt = f'''\ -{persona} + Parameters: + model (GenerativeModel): The generative model to use for content generation. + prompt (str): The prompt to generate content from. -Write a single sentence premise for a sci-fi story featuring cats.''' + Returns: + str: The generated content. + """ + try: + # FIXME: Need a progress bar here. + return model.generate_content(prompt, request_options={'retry':retry.Retry()}) + except Exception as e: + print(f"Error generating content: {e}") + return "" -outline_prompt = f'''\ -{persona} +def ai_story_generator(persona, story_genre, characters): + """ + Write a story using prompt chaining and iterative generation. -You have a gripping premise in mind: + Parameters: + persona (str): The persona statement for the author. + story_genre (str): The genre of the story. + characters (str): The characters in the story. + """ + print(f"Starting to write {story_genre} story based on characters: {characters}..") + try: + # Define persona and writing guidelines + guidelines = '''\ + Writing Guidelines -{{premise}} + Delve deeper. Lose yourself in the world you're building. Unleash vivid + descriptions to paint the scenes in your reader's mind. + Develop your characters—let their motivations, fears, and complexities unfold naturally. + Weave in the threads of your outline, but don't feel constrained by it. + Allow your story to surprise you as you write. Use rich imagery, sensory details, and + evocative language to bring the setting, characters, and events to life. + Introduce elements subtly that can blossom into complex subplots, relationships, + or worldbuilding details later in the story. + Keep things intriguing but not fully resolved. + Avoid boxing the story into a corner too early. + Plant the seeds of subplots or potential character arc shifts that can be expanded later. -Write an outline for the plot of your story.''' + Remember, your main goal is to write as much as you can. If you get through + the story too fast, that is bad. Expand, never summarize. + ''' -starting_prompt = f'''\ -{persona} + # Generate prompts + premise_prompt = f'''\ + {persona} -You have a gripping premise in mind: + Write a single sentence premise for a {story_genre} story featuring {characters}. + ''' -{{premise}} + outline_prompt = f'''\ + {persona} -Your imagination has crafted a rich narrative outline: + You have a gripping premise in mind: -{{outline}} + {{premise}} -First, silently review the outline and the premise. Consider how to start the -story. + Write an outline for the plot of your story. + ''' -Start to write the very beginning of the story. You are not expected to finish -the whole story now. Your writing should be detailed enough that you are only -scratching the surface of the first bullet of your outline. Try to write AT -MINIMUM 1000 WORDS. + starting_prompt = f'''\ + {persona} -{guidelines}''' + You have a gripping premise in mind: + + {{premise}} + + Your imagination has crafted a rich narrative outline: + + {{outline}} + + First, silently review the outline and the premise. Consider how to start the + story. + + Start to write the very beginning of the story. You are not expected to finish + the whole story now. Your writing should be detailed enough that you are only + scratching the surface of the first bullet of your outline. Try to write AT + MINIMUM 5000 WORDS. + + {guidelines} + ''' + + continuation_prompt = f'''\ + {persona} + + You have a gripping premise in mind: + + {{premise}} + + Your imagination has crafted a rich narrative outline: + + {{outline}} + + You've begun to immerse yourself in this world, and the words are flowing. + Here's what you've written so far: + + {{story_text}} + + ===== + + First, silently review the outline and story so far. Identify what the single + next part of your outline you should write. + + Your task is to continue where you left off and write the next part of the story. + You are not expected to finish the whole story now. Your writing should be + detailed enough that you are only scratching the surface of the next part of + your outline. Try to write AT MINIMUM 2000 WORDS. However, only once the story + is COMPLETELY finished, write IAMDONE. Remember, do NOT write a whole chapter + right now. + + {guidelines} + ''' + + # Configure generative AI + load_dotenv(Path('../.env')) + genai.configure(api_key=os.getenv('GEMINI_API_KEY')) + # Initialize the generative model + model = genai.GenerativeModel('gemini-1.0-pro') + + # Generate prompts + try: + premise = generate_with_retry(model, premise_prompt).text + print(f"The premise of the story is: {premise}") + except Exception as err: + print(f"Premise Generation Error: {err}") + return + + outline = generate_with_retry(model, outline_prompt.format(premise=premise)).text + print(f"The Outline of the story is: {outline}\n\n") + if not outline: + print("Failed to generate outline. Exiting...") + return + + # Generate starting draft + try: + starting_draft = generate_with_retry(model, + starting_prompt.format(premise=premise, outline=outline)).text + pprint(starting_draft) + except Exception as err: + print(f"Failed to Generate Story draft: {err}") + return + + try: + draft = starting_draft + continuation = generate_with_retry(model, + continuation_prompt.format(premise=premise, outline=outline, story_text=draft)).text + pprint(continuation) + except Exception as err: + print(f"Failed to write the initial draft: {err}") + + # Add the continuation to the initial draft, keep building the story until we see 'IAMDONE' + try: + draft += '\n\n' + continuation + except Exception as err: + print(f"Failed as: {err} and {continuation}") + while 'IAMDONE' not in continuation: + try: + continuation = generate_with_retry(model, + continuation_prompt.format(premise=premise, outline=outline, story_text=draft)).text + draft += '\n\n' + continuation + except Exception as err: + print(f"Failed to continually write the story: {err}") + return + + # Remove 'IAMDONE' and print the final story + final = draft.replace('IAMDONE', '').strip() + pprint(final) + + except Exception as e: + print(f"Main Story writing: An error occurred: {e}")