Wednesday, December 24, 2025

Building an LLM-Based Christmas Story Generator: A Guide to Creating Humorous, Emotional, and Romantic Holiday Tales



Introduction and Problem Analysis


Creating an LLM-based chatbot that generates Christmas short stories presents a fascinating intersection of natural language processing, creative writing, and holiday sentiment. The challenge lies in developing a system that can consistently produce engaging narratives across three distinct emotional tones: humor, emotion, and romance, while maintaining the festive Christmas atmosphere throughout each story.

The core problem involves several technical and creative components. First, we need to establish a robust foundation using a large language model that can understand context and generate coherent narratives. Second, we must implement tone control mechanisms that can reliably shift the story's emotional direction based on user preferences. Third, we need to ensure that each generated story maintains narrative structure, character development, and thematic consistency while incorporating Christmas elements naturally.

The system architecture requires careful consideration of prompt engineering, response filtering, and quality assurance mechanisms. We must also address the challenge of generating stories that are approximately 10,000 characters in length, which requires sophisticated content planning and pacing control.


System Architecture and Core Components


The foundation of our Christmas story generator rests on several interconnected components that work together to produce high-quality narratives. The primary component is the Large Language Model interface, which serves as the creative engine for story generation. This component handles the actual text generation process and maintains conversation context throughout the interaction.

The Prompt Engineering Module represents the most critical aspect of our system. This module crafts specialized prompts that guide the LLM toward generating stories with specific emotional tones while maintaining Christmas themes. The prompts must be sophisticated enough to encourage creativity while providing sufficient constraints to ensure consistent quality and appropriate content.

The Story Structure Controller manages narrative flow and ensures that generated stories follow traditional storytelling conventions. This component monitors story length, pacing, character development, and plot progression to maintain reader engagement throughout the approximately 10,000-character narrative.

The Tone Classification and Enhancement System analyzes user requests and applies appropriate emotional modifiers to the generation process. This system ensures that humorous stories incorporate comedic elements, emotional stories evoke genuine feelings, and romantic stories create meaningful connections between characters.

The Content Filter and Quality Assurance Module performs post-generation analysis to ensure that stories meet quality standards, maintain appropriate content, and successfully incorporate Christmas themes. This component also handles error detection and content refinement when necessary.


Prompt Engineering Strategies for Christmas Story Generation


Effective prompt engineering forms the cornerstone of successful story generation. The prompts must balance creative freedom with structural guidance to produce engaging narratives that meet specific requirements. For humorous Christmas stories, prompts should encourage playful scenarios, unexpected twists, and lighthearted character interactions while maintaining the warmth associated with the holiday season.

The prompt structure typically begins with context setting that establishes the Christmas atmosphere and introduces key thematic elements. This foundation includes references to traditional holiday symbols, seasonal weather, family gatherings, gift-giving traditions, and the general spirit of Christmas celebration.

Character development prompts focus on creating relatable protagonists who face Christmas-related challenges or opportunities. These characters should be well-rounded individuals with clear motivations, personality traits, and emotional depth that allows readers to connect with their journey throughout the story.

Plot development prompts guide the narrative structure by suggesting conflict introduction, character growth opportunities, and satisfying resolution pathways. The prompts must encourage stories that build tension appropriately, develop relationships meaningfully, and conclude with emotionally satisfying endings that reinforce Christmas themes.

Tone-specific prompts require careful calibration to achieve the desired emotional impact. Humorous prompts might suggest comedic situations, witty dialogue, or amusing misunderstandings. Emotional prompts could focus on themes of family reunion, personal growth, or overcoming challenges. Romantic prompts might emphasize connection, intimacy, and the magic of Christmas bringing people together.


Implementation of Core Functionality


The implementation begins with establishing the basic chatbot framework that can handle user interactions and maintain conversation context. This framework must be robust enough to handle various user inputs while maintaining focus on Christmas story generation.


import openai

import json

import re

from typing import Dict, List, Optional

from dataclasses import dataclass

from enum import Enum


class StoryTone(Enum):

    HUMOROUS = "humorous"

    EMOTIONAL = "emotional"

    ROMANTIC = "romantic"


@dataclass

class StoryRequest:

    tone: StoryTone

    characters: List[str]

    setting: str

    special_elements: List[str]

    target_length: int = 10000


class ChristmasStoryGenerator:

    def __init__(self, api_key: str):

        self.client = openai.OpenAI(api_key=api_key)

        self.conversation_history = []

        

    def generate_story(self, request: StoryRequest) -> str:

        prompt = self._build_prompt(request)

        response = self._call_llm(prompt)

        story = self._process_response(response)

        return self._ensure_length(story, request.target_length)


The story generation process begins with prompt construction that incorporates all necessary elements for creating engaging Christmas narratives. The prompt building function must carefully balance specificity with creative freedom to produce optimal results.


def _build_prompt(self, request: StoryRequest) -> str:

    base_prompt = """You are a master storyteller specializing in Christmas tales. 

    Create a captivating Christmas short story that embodies the magic and spirit 

    of the holiday season."""

    

    tone_instructions = {

        StoryTone.HUMOROUS: """Focus on creating a lighthearted, funny story 

        filled with comedic situations, witty dialogue, and amusing Christmas 

        mishaps. Include unexpected twists and playful character interactions 

        that will make readers smile and laugh.""",

        

        StoryTone.EMOTIONAL: """Craft a deeply moving story that explores themes 

        of family, love, forgiveness, hope, and the transformative power of 

        Christmas. Create moments that will touch readers' hearts and remind 

        them of what truly matters during the holiday season.""",

        

        StoryTone.ROMANTIC: """Develop a heartwarming romantic story that 

        captures the magic of Christmas love. Focus on the connection between 

        characters, the enchantment of the season, and how Christmas brings 

        people together in meaningful ways."""

    }

    

    structure_guidance = """

    Structure your story with:

    - An engaging opening that immediately establishes the Christmas setting

    - Well-developed characters with clear motivations and personalities

    - A compelling conflict or challenge that drives the narrative forward

    - Character growth and relationship development throughout the story

    - A satisfying resolution that reinforces Christmas themes and values

    - Rich descriptions of Christmas atmosphere, traditions, and emotions

    """

    

    character_instruction = ""

    if request.characters:

        character_instruction = f"Include these characters: {', '.join(request.characters)}. "

    

    setting_instruction = f"Set the story in: {request.setting}. "

    

    elements_instruction = ""

    if request.special_elements:

        elements_instruction = f"Incorporate these elements: {', '.join(request.special_elements)}. "

    

    length_instruction = f"""Create a story of approximately {request.target_length} 

    characters that maintains reader engagement throughout its entire length."""

    

    complete_prompt = f"""

    {base_prompt}

    

    {tone_instructions[request.tone]}

    

    {structure_guidance}

    

    {character_instruction}{setting_instruction}{elements_instruction}

    

    {length_instruction}

    

    Begin the story now:

    """

    

    return complete_prompt


The LLM interaction component handles communication with the language model while managing potential errors and ensuring reliable response generation. This component must be robust enough to handle various API responses and maintain consistent performance.


def _call_llm(self, prompt: str) -> str:

    try:

        response = self.client.chat.completions.create(

            model="gpt-4",

            messages=[

                {"role": "system", "content": "You are a professional Christmas story writer."},

                {"role": "user", "content": prompt}

            ],

            max_tokens=4000,

            temperature=0.8,

            presence_penalty=0.1,

            frequency_penalty=0.1

        )

        return response.choices[0].message.content

    except Exception as e:

        raise Exception(f"Error generating story: {str(e)}")


def _process_response(self, response: str) -> str:

    # Clean up the response and ensure proper formatting

    story = response.strip()

    

    # Remove any unwanted prefixes or suffixes

    story = re.sub(r'^(Here\'s|Here is).*?story:?\s*', '', story, flags=re.IGNORECASE)

    story = re.sub(r'\n\s*\n\s*\n', '\n\n', story)  # Normalize paragraph breaks

    

    return story


The length management system ensures that generated stories meet the target character count while maintaining narrative quality and coherence. This component may need to request additional content or perform intelligent truncation when necessary.


def _ensure_length(self, story: str, target_length: int) -> str:

    current_length = len(story)

    tolerance = 500  # Allow 500 character variance

    

    if abs(current_length - target_length) <= tolerance:

        return story

    

    if current_length < target_length - tolerance:

        # Story is too short, extend it

        return self._extend_story(story, target_length - current_length)

    else:

        # Story is too long, trim it intelligently

        return self._trim_story(story, target_length)


def _extend_story(self, story: str, additional_chars: int) -> str:

    extension_prompt = f"""

    Continue this Christmas story by adding approximately {additional_chars} 

    characters. Maintain the same tone, style, and characters. Add meaningful 

    content that enhances the narrative without feeling forced or repetitive.

    

    Current story:

    {story}

    

    Continue the story:

    """

    

    extension = self._call_llm(extension_prompt)

    return story + "\n\n" + extension


def _trim_story(self, story: str, target_length: int) -> str:

    # Intelligent trimming that preserves story structure

    sentences = story.split('.')

    trimmed_story = ""

    

    for sentence in sentences:

        if len(trimmed_story + sentence + '.') <= target_length:

            trimmed_story += sentence + '.'

        else:

            break

    

    # Ensure the story ends properly

    if not trimmed_story.endswith('.'):

        trimmed_story = trimmed_story.rsplit(' ', 1)[0] + '.'

    

    return trimmed_story


Advanced Features and Customization Options


The chatbot interface provides users with intuitive controls for customizing their story generation experience. Users can specify character names, settings, special elements to include, and preferred story tone through natural language interactions.


class ChristmasStoryChatbot:

    def __init__(self, api_key: str):

        self.generator = ChristmasStoryGenerator(api_key)

        self.current_session = {}

        

    def process_user_input(self, user_input: str) -> str:

        intent = self._analyze_intent(user_input)

        

        if intent == "generate_story":

            return self._handle_story_generation(user_input)

        elif intent == "modify_request":

            return self._handle_modification(user_input)

        elif intent == "help":

            return self._provide_help()

        else:

            return self._handle_general_conversation(user_input)

    

    def _analyze_intent(self, user_input: str) -> str:

        input_lower = user_input.lower()

        

        story_keywords = ["story", "tale", "write", "create", "generate"]

        modify_keywords = ["change", "modify", "different", "another"]

        help_keywords = ["help", "how", "what", "explain"]

        

        if any(keyword in input_lower for keyword in story_keywords):

            return "generate_story"

        elif any(keyword in input_lower for keyword in modify_keywords):

            return "modify_request"

        elif any(keyword in input_lower for keyword in help_keywords):

            return "help"

        else:

            return "general_conversation"


The story customization system extracts user preferences from natural language input and translates them into structured story generation parameters. This system must be sophisticated enough to handle various ways users might express their preferences.


def _extract_story_parameters(self, user_input: str) -> StoryRequest:

    # Extract tone preference

    tone = StoryTone.EMOTIONAL  # Default

    if any(word in user_input.lower() for word in ["funny", "humorous", "comedy", "laugh"]):

        tone = StoryTone.HUMOROUS

    elif any(word in user_input.lower() for word in ["romantic", "love", "romance"]):

        tone = StoryTone.ROMANTIC

    

    # Extract character names

    characters = []

    character_pattern = r"characters?\s+(?:named\s+|called\s+)?([A-Z][a-z]+(?:\s+and\s+[A-Z][a-z]+)*)"

    character_match = re.search(character_pattern, user_input, re.IGNORECASE)

    if character_match:

        character_names = character_match.group(1)

        characters = [name.strip() for name in re.split(r'\s+and\s+', character_names)]

    

    # Extract setting

    setting = "a cozy Christmas town"  # Default

    setting_pattern = r"(?:set in|takes? place in|located in)\s+([^.!?]+)"

    setting_match = re.search(setting_pattern, user_input, re.IGNORECASE)

    if setting_match:

        setting = setting_match.group(1).strip()

    

    # Extract special elements

    special_elements = []

    element_keywords = {

        "snow": ["snow", "snowfall", "blizzard"],

        "fireplace": ["fireplace", "fire", "hearth"],

        "gifts": ["gifts", "presents", "packages"],

        "family": ["family", "relatives", "reunion"],

        "magic": ["magic", "magical", "miracle"]

    }

    

    for element, keywords in element_keywords.items():

        if any(keyword in user_input.lower() for keyword in keywords):

            special_elements.append(element)

    

    return StoryRequest(

        tone=tone,

        characters=characters,

        setting=setting,

        special_elements=special_elements

    )


Quality Assurance and Content Validation


The quality assurance system evaluates generated stories across multiple dimensions to ensure they meet established standards for narrative quality, thematic consistency, and emotional impact. This system performs automated analysis of story structure, character development, and Christmas theme integration.


class StoryQualityAnalyzer:

    def __init__(self):

        self.christmas_keywords = [

            "christmas", "holiday", "santa", "reindeer", "snow", "gift",

            "present", "tree", "ornament", "carol", "bell", "star",

            "fireplace", "family", "celebration", "winter", "december"

        ]

        

    def analyze_story_quality(self, story: str, tone: StoryTone) -> Dict[str, float]:

        scores = {

            "christmas_theme": self._analyze_christmas_theme(story),

            "narrative_structure": self._analyze_narrative_structure(story),

            "tone_consistency": self._analyze_tone_consistency(story, tone),

            "character_development": self._analyze_character_development(story),

            "emotional_impact": self._analyze_emotional_impact(story, tone)

        }

        

        return scores

    

    def _analyze_christmas_theme(self, story: str) -> float:

        story_lower = story.lower()

        keyword_count = sum(1 for keyword in self.christmas_keywords 

                          if keyword in story_lower)

        

        # Score based on keyword density and distribution

        story_length = len(story.split())

        keyword_density = keyword_count / story_length if story_length > 0 else 0

        

        # Optimal density is around 2-5% for natural integration

        if 0.02 <= keyword_density <= 0.05:

            return 1.0

        elif keyword_density < 0.02:

            return keyword_density / 0.02

        else:

            return max(0.5, 1.0 - (keyword_density - 0.05) * 5)

    

    def _analyze_narrative_structure(self, story: str) -> float:

        paragraphs = [p.strip() for p in story.split('\n\n') if p.strip()]

        

        if len(paragraphs) < 3:

            return 0.3  # Too short for proper structure

        

        # Check for story progression indicators

        beginning_indicators = ["once", "it was", "the day", "christmas eve"]

        middle_indicators = ["suddenly", "then", "however", "meanwhile"]

        ending_indicators = ["finally", "at last", "in the end", "christmas morning"]

        

        story_lower = story.lower()

        has_beginning = any(indicator in story_lower[:len(story)//3] 

                          for indicator in beginning_indicators)

        has_middle = any(indicator in story_lower[len(story)//3:2*len(story)//3] 

                        for indicator in middle_indicators)

        has_ending = any(indicator in story_lower[2*len(story)//3:] 

                        for indicator in ending_indicators)

        

        structure_score = (has_beginning + has_middle + has_ending) / 3

        return structure_score


The content validation system ensures that generated stories maintain appropriate content standards while preserving creative expression. This system identifies potential issues and suggests improvements when necessary.


def _analyze_tone_consistency(self, story: str, target_tone: StoryTone) -> float:

    tone_indicators = {

        StoryTone.HUMOROUS: {

            "positive": ["laughed", "chuckled", "giggled", "amusing", "funny", 

                        "hilarious", "comical", "silly", "absurd"],

            "negative": ["cried", "sobbed", "tragic", "devastating", "heartbreaking"]

        },

        StoryTone.EMOTIONAL: {

            "positive": ["tears", "moved", "touched", "heartwarming", "meaningful",

                        "profound", "emotional", "feelings"],

            "negative": ["laughed", "hilarious", "ridiculous", "absurd"]

        },

        StoryTone.ROMANTIC: {

            "positive": ["love", "heart", "kiss", "embrace", "romantic", "tender",

                        "passion", "affection", "beloved"],

            "negative": ["hatred", "disgusting", "repulsive", "enemy"]

        }

    }

    

    story_lower = story.lower()

    indicators = tone_indicators[target_tone]

    

    positive_count = sum(1 for word in indicators["positive"] if word in story_lower)

    negative_count = sum(1 for word in indicators["negative"] if word in story_lower)

    

    if positive_count == 0 and negative_count == 0:

        return 0.5  # Neutral, neither positive nor negative

    

    consistency_score = positive_count / (positive_count + negative_count * 2)

    return min(1.0, consistency_score)


def _analyze_character_development(self, story: str) -> float:

    # Look for character names and development indicators

    sentences = story.split('.')

    character_names = set()

    

    # Extract potential character names (capitalized words that aren't common nouns)

    common_words = {"Christmas", "Santa", "December", "Holiday", "The", "And", "But"}

    

    for sentence in sentences:

        words = sentence.split()

        for word in words:

            if (word.isalpha() and word[0].isupper() and 

                word not in common_words and len(word) > 2):

                character_names.add(word)

    

    # Analyze character development through dialogue and action

    dialogue_count = story.count('"')

    action_indicators = ["said", "thought", "felt", "realized", "decided", "remembered"]

    action_count = sum(1 for indicator in action_indicators 

                      if indicator in story.lower())

    

    development_score = min(1.0, (len(character_names) * 0.3 + 

                                 dialogue_count * 0.02 + 

                                 action_count * 0.05))

    return development_score


User Interface and Interaction Design


The conversational interface provides users with an intuitive way to interact with the story generation system. The interface must be responsive, helpful, and capable of guiding users through the story creation process while maintaining engagement throughout the interaction.


def _handle_story_generation(self, user_input: str) -> str:

    try:

        story_request = self._extract_story_parameters(user_input)

        

        # Generate the story

        story = self.generator.generate_story(story_request)

        

        # Analyze quality

        analyzer = StoryQualityAnalyzer()

        quality_scores = analyzer.analyze_story_quality(story, story_request.tone)

        

        # Store in session for potential modifications

        self.current_session["last_story"] = story

        self.current_session["last_request"] = story_request

        self.current_session["quality_scores"] = quality_scores

        

        # Prepare response

        response = f"Here's your {story_request.tone.value} Christmas story:\n\n"

        response += story

        response += f"\n\n--- Story Complete ---"

        response += f"\nStory length: {len(story)} characters"

        

        # Add quality feedback if scores are low

        avg_quality = sum(quality_scores.values()) / len(quality_scores)

        if avg_quality < 0.7:

            response += "\n\nWould you like me to regenerate the story with different parameters?"

        

        return response

        

    except Exception as e:

        return f"I apologize, but I encountered an error while generating your story: {str(e)}. Please try again with a different request."


def _provide_help(self) -> str:

    help_text = """

I'm your Christmas Story Generator! I can create magical Christmas tales in three different styles:


🎭 HUMOROUS STORIES: Funny, lighthearted tales filled with Christmas comedy and amusing situations

💝 EMOTIONAL STORIES: Heartwarming stories that explore deep feelings and Christmas spirit  

💕 ROMANTIC STORIES: Love stories set during the magical Christmas season


To request a story, simply tell me:

- What tone you'd like (funny, emotional, or romantic)

- Any character names you want included

- The setting where you'd like the story to take place

- Special elements to include (snow, fireplace, gifts, etc.)


Example requests:

"Write a funny Christmas story about characters named Sarah and Mike in a small town"

"Create an emotional Christmas tale set in a cozy cabin with a fireplace"

"Generate a romantic Christmas story with snow and Christmas lights"


Each story will be approximately 10,000 characters long and filled with Christmas magic!


What kind of Christmas story would you like me to create for you?

    """

    return help_text.strip()


The session management system maintains conversation context and allows users to request modifications or variations of previously generated stories. This system enhances user experience by providing continuity and flexibility in the story creation process.


def _handle_modification(self, user_input: str) -> str:

    if "last_story" not in self.current_session:

        return "I don't have a previous story to modify. Please request a new story first!"

    

    modification_type = self._identify_modification_type(user_input)

    

    if modification_type == "tone_change":

        return self._modify_story_tone(user_input)

    elif modification_type == "character_change":

        return self._modify_story_characters(user_input)

    elif modification_type == "setting_change":

        return self._modify_story_setting(user_input)

    elif modification_type == "regenerate":

        return self._regenerate_story()

    else:

        return "I'm not sure what modification you'd like. You can ask me to change the tone, characters, setting, or regenerate the story completely."


def _modify_story_tone(self, user_input: str) -> str:

    new_request = self.current_session["last_request"]

    

    # Extract new tone from user input

    if any(word in user_input.lower() for word in ["funny", "humorous", "comedy"]):

        new_request.tone = StoryTone.HUMOROUS

    elif any(word in user_input.lower() for word in ["romantic", "love"]):

        new_request.tone = StoryTone.ROMANTIC

    elif any(word in user_input.lower() for word in ["emotional", "heartwarming"]):

        new_request.tone = StoryTone.EMOTIONAL

    

    # Generate new story with modified tone

    new_story = self.generator.generate_story(new_request)

    self.current_session["last_story"] = new_story

    

    return f"Here's your story with a {new_request.tone.value} tone:\n\n{new_story}"


Performance Optimization and Error Handling


The system implements comprehensive error handling and performance optimization strategies to ensure reliable operation under various conditions. Error handling covers API failures, invalid user inputs, and unexpected system states while maintaining user experience quality.


class ErrorHandler:

    def __init__(self):

        self.retry_count = 3

        self.fallback_responses = {

            "api_error": "I'm experiencing technical difficulties. Please try again in a moment.",

            "invalid_input": "I didn't quite understand that request. Could you please rephrase it?",

            "generation_failed": "I wasn't able to generate a story with those parameters. Let's try something different.",

            "timeout": "The story generation is taking longer than expected. Please try a simpler request."

        }

    

    def handle_api_error(self, error: Exception, retry_func, *args, **kwargs):

        for attempt in range(self.retry_count):

            try:

                return retry_func(*args, **kwargs)

            except Exception as e:

                if attempt == self.retry_count - 1:

                    return self.fallback_responses["api_error"]

                time.sleep(2 ** attempt)  # Exponential backoff

        

    def validate_story_request(self, request: StoryRequest) -> Optional[str]:

        if not isinstance(request.tone, StoryTone):

            return "Invalid story tone specified."

        

        if request.target_length < 1000 or request.target_length > 20000:

            return "Story length must be between 1,000 and 20,000 characters."

        

        if len(request.characters) > 5:

            return "Please limit character requests to 5 or fewer names."

        

        return None  # No validation errors


Performance optimization focuses on efficient API usage, response caching, and intelligent content management to minimize generation time and computational resources while maintaining story quality.


class PerformanceOptimizer:

    def __init__(self):

        self.story_cache = {}

        self.cache_size_limit = 100

        

    def cache_story(self, request_hash: str, story: str):

        if len(self.story_cache) >= self.cache_size_limit:

            # Remove oldest entry

            oldest_key = next(iter(self.story_cache))

            del self.story_cache[oldest_key]

        

        self.story_cache[request_hash] = {

            "story": story,

            "timestamp": time.time()

        }

    

    def get_cached_story(self, request_hash: str) -> Optional[str]:

        if request_hash in self.story_cache:

            cache_entry = self.story_cache[request_hash]

            # Cache expires after 1 hour

            if time.time() - cache_entry["timestamp"] < 3600:

                return cache_entry["story"]

            else:

                del self.story_cache[request_hash]

        

        return None

    

    def generate_request_hash(self, request: StoryRequest) -> str:

        import hashlib

        request_string = f"{request.tone.value}_{request.setting}_{'_'.join(request.characters)}_{'_'.join(request.special_elements)}"

        return hashlib.md5(request_string.encode()).hexdigest()



Complete Working Example


The following complete implementation demonstrates all components working together to create a fully functional Christmas story generator chatbot. This example includes all necessary imports, error handling, and user interaction capabilities.


import openai

import json

import re

import time

import hashlib

from typing import Dict, List, Optional

from dataclasses import dataclass

from enum import Enum


class StoryTone(Enum):

    HUMOROUS = "humorous"

    EMOTIONAL = "emotional"

    ROMANTIC = "romantic"


@dataclass

class StoryRequest:

    tone: StoryTone

    characters: List[str]

    setting: str

    special_elements: List[str]

    target_length: int = 10000


class StoryQualityAnalyzer:

    def __init__(self):

        self.christmas_keywords = [

            "christmas", "holiday", "santa", "reindeer", "snow", "gift",

            "present", "tree", "ornament", "carol", "bell", "star",

            "fireplace", "family", "celebration", "winter", "december"

        ]

        

    def analyze_story_quality(self, story: str, tone: StoryTone) -> Dict[str, float]:

        scores = {

            "christmas_theme": self._analyze_christmas_theme(story),

            "narrative_structure": self._analyze_narrative_structure(story),

            "tone_consistency": self._analyze_tone_consistency(story, tone),

            "character_development": self._analyze_character_development(story),

            "emotional_impact": self._analyze_emotional_impact(story, tone)

        }

        return scores

    

    def _analyze_christmas_theme(self, story: str) -> float:

        story_lower = story.lower()

        keyword_count = sum(1 for keyword in self.christmas_keywords 

                          if keyword in story_lower)

        story_length = len(story.split())

        keyword_density = keyword_count / story_length if story_length > 0 else 0

        

        if 0.02 <= keyword_density <= 0.05:

            return 1.0

        elif keyword_density < 0.02:

            return keyword_density / 0.02

        else:

            return max(0.5, 1.0 - (keyword_density - 0.05) * 5)

    

    def _analyze_narrative_structure(self, story: str) -> float:

        paragraphs = [p.strip() for p in story.split('\n\n') if p.strip()]

        if len(paragraphs) < 3:

            return 0.3

        

        beginning_indicators = ["once", "it was", "the day", "christmas eve"]

        middle_indicators = ["suddenly", "then", "however", "meanwhile"]

        ending_indicators = ["finally", "at last", "in the end", "christmas morning"]

        

        story_lower = story.lower()

        has_beginning = any(indicator in story_lower[:len(story)//3] 

                          for indicator in beginning_indicators)

        has_middle = any(indicator in story_lower[len(story)//3:2*len(story)//3] 

                        for indicator in middle_indicators)

        has_ending = any(indicator in story_lower[2*len(story)//3:] 

                        for indicator in ending_indicators)

        

        return (has_beginning + has_middle + has_ending) / 3

    

    def _analyze_tone_consistency(self, story: str, target_tone: StoryTone) -> float:

        tone_indicators = {

            StoryTone.HUMOROUS: {

                "positive": ["laughed", "chuckled", "giggled", "amusing", "funny", 

                            "hilarious", "comical", "silly", "absurd"],

                "negative": ["cried", "sobbed", "tragic", "devastating", "heartbreaking"]

            },

            StoryTone.EMOTIONAL: {

                "positive": ["tears", "moved", "touched", "heartwarming", "meaningful",

                            "profound", "emotional", "feelings"],

                "negative": ["laughed", "hilarious", "ridiculous", "absurd"]

            },

            StoryTone.ROMANTIC: {

                "positive": ["love", "heart", "kiss", "embrace", "romantic", "tender",

                            "passion", "affection", "beloved"],

                "negative": ["hatred", "disgusting", "repulsive", "enemy"]

            }

        }

        

        story_lower = story.lower()

        indicators = tone_indicators[target_tone]

        

        positive_count = sum(1 for word in indicators["positive"] if word in story_lower)

        negative_count = sum(1 for word in indicators["negative"] if word in story_lower)

        

        if positive_count == 0 and negative_count == 0:

            return 0.5

        

        consistency_score = positive_count / (positive_count + negative_count * 2)

        return min(1.0, consistency_score)

    

    def _analyze_character_development(self, story: str) -> float:

        sentences = story.split('.')

        character_names = set()

        common_words = {"Christmas", "Santa", "December", "Holiday", "The", "And", "But"}

        

        for sentence in sentences:

            words = sentence.split()

            for word in words:

                if (word.isalpha() and word[0].isupper() and 

                    word not in common_words and len(word) > 2):

                    character_names.add(word)

        

        dialogue_count = story.count('"')

        action_indicators = ["said", "thought", "felt", "realized", "decided", "remembered"]

        action_count = sum(1 for indicator in action_indicators 

                          if indicator in story.lower())

        

        development_score = min(1.0, (len(character_names) * 0.3 + 

                                     dialogue_count * 0.02 + 

                                     action_count * 0.05))

        return development_score

    

    def _analyze_emotional_impact(self, story: str, tone: StoryTone) -> float:

        emotional_words = {

            "joy", "happiness", "love", "warmth", "comfort", "peace",

            "sadness", "tears", "longing", "hope", "wonder", "magic"

        }

        

        story_lower = story.lower()

        emotional_count = sum(1 for word in emotional_words if word in story_lower)

        story_length = len(story.split())

        

        emotional_density = emotional_count / story_length if story_length > 0 else 0

        return min(1.0, emotional_density * 50)


class ErrorHandler:

    def __init__(self):

        self.retry_count = 3

        self.fallback_responses = {

            "api_error": "I'm experiencing technical difficulties. Please try again in a moment.",

            "invalid_input": "I didn't quite understand that request. Could you please rephrase it?",

            "generation_failed": "I wasn't able to generate a story with those parameters. Let's try something different.",

            "timeout": "The story generation is taking longer than expected. Please try a simpler request."

        }

    

    def handle_api_error(self, error: Exception, retry_func, *args, **kwargs):

        for attempt in range(self.retry_count):

            try:

                return retry_func(*args, **kwargs)

            except Exception as e:

                if attempt == self.retry_count - 1:

                    return self.fallback_responses["api_error"]

                time.sleep(2 ** attempt)

        

    def validate_story_request(self, request: StoryRequest) -> Optional[str]:

        if not isinstance(request.tone, StoryTone):

            return "Invalid story tone specified."

        

        if request.target_length < 1000 or request.target_length > 20000:

            return "Story length must be between 1,000 and 20,000 characters."

        

        if len(request.characters) > 5:

            return "Please limit character requests to 5 or fewer names."

        

        return None


class PerformanceOptimizer:

    def __init__(self):

        self.story_cache = {}

        self.cache_size_limit = 100

        

    def cache_story(self, request_hash: str, story: str):

        if len(self.story_cache) >= self.cache_size_limit:

            oldest_key = next(iter(self.story_cache))

            del self.story_cache[oldest_key]

        

        self.story_cache[request_hash] = {

            "story": story,

            "timestamp": time.time()

        }

    

    def get_cached_story(self, request_hash: str) -> Optional[str]:

        if request_hash in self.story_cache:

            cache_entry = self.story_cache[request_hash]

            if time.time() - cache_entry["timestamp"] < 3600:

                return cache_entry["story"]

            else:

                del self.story_cache[request_hash]

        return None

    

    def generate_request_hash(self, request: StoryRequest) -> str:

        request_string = f"{request.tone.value}_{request.setting}_{'_'.join(request.characters)}_{'_'.join(request.special_elements)}"

        return hashlib.md5(request_string.encode()).hexdigest()


class ChristmasStoryGenerator:

    def __init__(self, api_key: str):

        self.client = openai.OpenAI(api_key=api_key)

        self.conversation_history = []

        self.error_handler = ErrorHandler()

        self.optimizer = PerformanceOptimizer()

        

    def generate_story(self, request: StoryRequest) -> str:

        validation_error = self.error_handler.validate_story_request(request)

        if validation_error:

            raise ValueError(validation_error)

        

        request_hash = self.optimizer.generate_request_hash(request)

        cached_story = self.optimizer.get_cached_story(request_hash)

        

        if cached_story:

            return cached_story

        

        prompt = self._build_prompt(request)

        response = self._call_llm(prompt)

        story = self._process_response(response)

        final_story = self._ensure_length(story, request.target_length)

        

        self.optimizer.cache_story(request_hash, final_story)

        return final_story

    

    def _build_prompt(self, request: StoryRequest) -> str:

        base_prompt = """You are a master storyteller specializing in Christmas tales. 

        Create a captivating Christmas short story that embodies the magic and spirit 

        of the holiday season."""

        

        tone_instructions = {

            StoryTone.HUMOROUS: """Focus on creating a lighthearted, funny story 

            filled with comedic situations, witty dialogue, and amusing Christmas 

            mishaps. Include unexpected twists and playful character interactions 

            that will make readers smile and laugh.""",

            

            StoryTone.EMOTIONAL: """Craft a deeply moving story that explores themes 

            of family, love, forgiveness, hope, and the transformative power of 

            Christmas. Create moments that will touch readers' hearts and remind 

            them of what truly matters during the holiday season.""",

            

            StoryTone.ROMANTIC: """Develop a heartwarming romantic story that 

            captures the magic of Christmas love. Focus on the connection between 

            characters, the enchantment of the season, and how Christmas brings 

            people together in meaningful ways."""

        }

        

        structure_guidance = """

        Structure your story with:

        - An engaging opening that immediately establishes the Christmas setting

        - Well-developed characters with clear motivations and personalities

        - A compelling conflict or challenge that drives the narrative forward

        - Character growth and relationship development throughout the story

        - A satisfying resolution that reinforces Christmas themes and values

        - Rich descriptions of Christmas atmosphere, traditions, and emotions

        """

        

        character_instruction = ""

        if request.characters:

            character_instruction = f"Include these characters: {', '.join(request.characters)}. "

        

        setting_instruction = f"Set the story in: {request.setting}. "

        

        elements_instruction = ""

        if request.special_elements:

            elements_instruction = f"Incorporate these elements: {', '.join(request.special_elements)}. "

        

        length_instruction = f"""Create a story of approximately {request.target_length} 

        characters that maintains reader engagement throughout its entire length."""

        

        complete_prompt = f"""

        {base_prompt}

        

        {tone_instructions[request.tone]}

        

        {structure_guidance}

        

        {character_instruction}{setting_instruction}{elements_instruction}

        

        {length_instruction}

        

        Begin the story now:

        """

        

        return complete_prompt

    

    def _call_llm(self, prompt: str) -> str:

        try:

            response = self.client.chat.completions.create(

                model="gpt-4",

                messages=[

                    {"role": "system", "content": "You are a professional Christmas story writer."},

                    {"role": "user", "content": prompt}

                ],

                max_tokens=4000,

                temperature=0.8,

                presence_penalty=0.1,

                frequency_penalty=0.1

            )

            return response.choices[0].message.content

        except Exception as e:

            raise Exception(f"Error generating story: {str(e)}")


    def _process_response(self, response: str) -> str:

        story = response.strip()

        story = re.sub(r'^(Here\'s|Here is).*?story:?\s*', '', story, flags=re.IGNORECASE)

        story = re.sub(r'\n\s*\n\s*\n', '\n\n', story)

        return story


    def _ensure_length(self, story: str, target_length: int) -> str:

        current_length = len(story)

        tolerance = 500

        

        if abs(current_length - target_length) <= tolerance:

            return story

        

        if current_length < target_length - tolerance:

            return self._extend_story(story, target_length - current_length)

        else:

            return self._trim_story(story, target_length)


    def _extend_story(self, story: str, additional_chars: int) -> str:

        extension_prompt = f"""

        Continue this Christmas story by adding approximately {additional_chars} 

        characters. Maintain the same tone, style, and characters. Add meaningful 

        content that enhances the narrative without feeling forced or repetitive.

        

        Current story:

        {story}

        

        Continue the story:

        """

        

        extension = self._call_llm(extension_prompt)

        return story + "\n\n" + extension


    def _trim_story(self, story: str, target_length: int) -> str:

        sentences = story.split('.')

        trimmed_story = ""

        

        for sentence in sentences:

            if len(trimmed_story + sentence + '.') <= target_length:

                trimmed_story += sentence + '.'

            else:

                break

        

        if not trimmed_story.endswith('.'):

            trimmed_story = trimmed_story.rsplit(' ', 1)[0] + '.'

        

        return trimmed_story


class ChristmasStoryChatbot:

    def __init__(self, api_key: str):

        self.generator = ChristmasStoryGenerator(api_key)

        self.current_session = {}

        self.analyzer = StoryQualityAnalyzer()

        

    def process_user_input(self, user_input: str) -> str:

        intent = self._analyze_intent(user_input)

        

        if intent == "generate_story":

            return self._handle_story_generation(user_input)

        elif intent == "modify_request":

            return self._handle_modification(user_input)

        elif intent == "help":

            return self._provide_help()

        else:

            return self._handle_general_conversation(user_input)

    

    def _analyze_intent(self, user_input: str) -> str:

        input_lower = user_input.lower()

        

        story_keywords = ["story", "tale", "write", "create", "generate"]

        modify_keywords = ["change", "modify", "different", "another"]

        help_keywords = ["help", "how", "what", "explain"]

        

        if any(keyword in input_lower for keyword in story_keywords):

            return "generate_story"

        elif any(keyword in input_lower for keyword in modify_keywords):

            return "modify_request"

        elif any(keyword in input_lower for keyword in help_keywords):

            return "help"

        else:

            return "general_conversation"

    

    def _extract_story_parameters(self, user_input: str) -> StoryRequest:

        tone = StoryTone.EMOTIONAL

        if any(word in user_input.lower() for word in ["funny", "humorous", "comedy", "laugh"]):

            tone = StoryTone.HUMOROUS

        elif any(word in user_input.lower() for word in ["romantic", "love", "romance"]):

            tone = StoryTone.ROMANTIC

        

        characters = []

        character_pattern = r"characters?\s+(?:named\s+|called\s+)?([A-Z][a-z]+(?:\s+and\s+[A-Z][a-z]+)*)"

        character_match = re.search(character_pattern, user_input, re.IGNORECASE)

        if character_match:

            character_names = character_match.group(1)

            characters = [name.strip() for name in re.split(r'\s+and\s+', character_names)]

        

        setting = "a cozy Christmas town"

        setting_pattern = r"(?:set in|takes? place in|located in)\s+([^.!?]+)"

        setting_match = re.search(setting_pattern, user_input, re.IGNORECASE)

        if setting_match:

            setting = setting_match.group(1).strip()

        

        special_elements = []

        element_keywords = {

            "snow": ["snow", "snowfall", "blizzard"],

            "fireplace": ["fireplace", "fire", "hearth"],

            "gifts": ["gifts", "presents", "packages"],

            "family": ["family", "relatives", "reunion"],

            "magic": ["magic", "magical", "miracle"]

        }

        

        for element, keywords in element_keywords.items():

            if any(keyword in user_input.lower() for keyword in keywords):

                special_elements.append(element)

        

        return StoryRequest(

            tone=tone,

            characters=characters,

            setting=setting,

            special_elements=special_elements

        )

    

    def _handle_story_generation(self, user_input: str) -> str:

        try:

            story_request = self._extract_story_parameters(user_input)

            story = self.generator.generate_story(story_request)

            quality_scores = self.analyzer.analyze_story_quality(story, story_request.tone)

            

            self.current_session["last_story"] = story

            self.current_session["last_request"] = story_request

            self.current_session["quality_scores"] = quality_scores

            

            response = f"Here's your {story_request.tone.value} Christmas story:\n\n"

            response += story

            response += f"\n\n--- Story Complete ---"

            response += f"\nStory length: {len(story)} characters"

            

            avg_quality = sum(quality_scores.values()) / len(quality_scores)

            if avg_quality < 0.7:

                response += "\n\nWould you like me to regenerate the story with different parameters?"

            

            return response

            

        except Exception as e:

            return f"I apologize, but I encountered an error while generating your story: {str(e)}. Please try again with a different request."


    def _handle_modification(self, user_input: str) -> str:

        if "last_story" not in self.current_session:

            return "I don't have a previous story to modify. Please request a new story first!"

        

        modification_type = self._identify_modification_type(user_input)

        

        if modification_type == "tone_change":

            return self._modify_story_tone(user_input)

        elif modification_type == "regenerate":

            return self._regenerate_story()

        else:

            return "I'm not sure what modification you'd like. You can ask me to change the tone or regenerate the story completely."


    def _identify_modification_type(self, user_input: str) -> str:

        input_lower = user_input.lower()

        

        if any(word in input_lower for word in ["tone", "style", "funny", "romantic", "emotional"]):

            return "tone_change"

        elif any(word in input_lower for word in ["regenerate", "new", "different", "again"]):

            return "regenerate"

        else:

            return "unknown"


    def _modify_story_tone(self, user_input: str) -> str:

        new_request = self.current_session["last_request"]

        

        if any(word in user_input.lower() for word in ["funny", "humorous", "comedy"]):

            new_request.tone = StoryTone.HUMOROUS

        elif any(word in user_input.lower() for word in ["romantic", "love"]):

            new_request.tone = StoryTone.ROMANTIC

        elif any(word in user_input.lower() for word in ["emotional", "heartwarming"]):

            new_request.tone = StoryTone.EMOTIONAL

        

        new_story = self.generator.generate_story(new_request)

        self.current_session["last_story"] = new_story

        

        return f"Here's your story with a {new_request.tone.value} tone:\n\n{new_story}"


    def _regenerate_story(self) -> str:

        request = self.current_session["last_request"]

        new_story = self.generator.generate_story(request)

        self.current_session["last_story"] = new_story

        

        return f"Here's a new version of your {request.tone.value} Christmas story:\n\n{new_story}"


    def _provide_help(self) -> str:

        help_text = """

I'm your Christmas Story Generator! I can create magical Christmas tales in three different styles:


🎭 HUMOROUS STORIES: Funny, lighthearted tales filled with Christmas comedy and amusing situations

💝 EMOTIONAL STORIES: Heartwarming stories that explore deep feelings and Christmas spirit  

💕 ROMANTIC STORIES: Love stories set during the magical Christmas season


To request a story, simply tell me:

- What tone you'd like (funny, emotional, or romantic)

- Any character names you want included

- The setting where you'd like the story to take place

- Special elements to include (snow, fireplace, gifts, etc.)


Example requests:

"Write a funny Christmas story about characters named Sarah and Mike in a small town"

"Create an emotional Christmas tale set in a cozy cabin with a fireplace"

"Generate a romantic Christmas story with snow and Christmas lights"


Each story will be approximately 10,000 characters long and filled with Christmas magic!


What kind of Christmas story would you like me to create for you?

        """

        return help_text.strip()


    def _handle_general_conversation(self, user_input: str) -> str:

        return "I'm here to help you create wonderful Christmas stories! Ask me to write a story, or say 'help' to learn more about what I can do."


def main():

    # Initialize the chatbot with your OpenAI API key

    api_key = "your-openai-api-key-here"  # Replace with actual API key

    chatbot = ChristmasStoryChatbot(api_key)

    

    print("🎄 Welcome to the Christmas Story Generator! 🎄")

    print("I can create humorous, emotional, or romantic Christmas stories for you.")

    print("Type 'help' for instructions or 'quit' to exit.\n")

    

    while True:

        user_input = input("You: ").strip()

        

        if user_input.lower() in ['quit', 'exit', 'bye']:

            print("🎄 Merry Christmas and happy storytelling! 🎄")

            break

        

        if not user_input:

            continue

        

        try:

            response = chatbot.process_user_input(user_input)

            print(f"\nChristmas Story Bot: {response}\n")

        except Exception as e:

            print(f"Sorry, I encountered an error: {str(e)}\n")


if __name__ == "__main__":

    main()


This comprehensive implementation provides a fully functional Christmas story generator that can create engaging narratives across multiple emotional tones while maintaining high quality standards and providing an intuitive user experience. The system incorporates advanced features such as caching, error handling, quality analysis, and conversation management to deliver a professional-grade storytelling application.