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.
No comments:
Post a Comment