AI Backlinker, Google Ads Generator, Letter Writer - WIP
This commit is contained in:
493
lib/ai_writers/ai_letter_writer/utils/letter_analyzer.py
Normal file
493
lib/ai_writers/ai_letter_writer/utils/letter_analyzer.py
Normal file
@@ -0,0 +1,493 @@
|
||||
"""
|
||||
Letter Analyzer Utility
|
||||
|
||||
This module provides functions for analyzing letter content, including tone,
|
||||
formality, readability, and offering basic suggestions for improvement.
|
||||
Note: The analysis methods provided here are simplified rule-based and
|
||||
keyword-based approaches. For more sophisticated analysis in a production
|
||||
environment, consider using advanced Natural Language Processing (NLP)
|
||||
libraries and models.
|
||||
"""
|
||||
|
||||
import re
|
||||
from typing import Dict, Any, Tuple, List
|
||||
|
||||
def analyze_letter_tone(content: str) -> Dict[str, float]:
|
||||
"""
|
||||
Analyze the tone of a letter based on the presence of specific keywords
|
||||
and phrases.
|
||||
|
||||
Args:
|
||||
content: The letter content to analyze.
|
||||
|
||||
Returns:
|
||||
Dictionary with tone scores (formal, friendly, assertive, etc.).
|
||||
Scores are based on the frequency of matching patterns and capped at 1.0.
|
||||
"""
|
||||
# This is a simplified version using keyword matching.
|
||||
# A more sophisticated approach would involve NLP libraries for sentiment and tone analysis.
|
||||
|
||||
# Initialize tone scores
|
||||
# Scores are arbitrary counts normalized in a simple way
|
||||
tone_scores = {
|
||||
"formal": 0.0,
|
||||
"friendly": 0.0,
|
||||
"assertive": 0.0,
|
||||
"respectful": 0.0,
|
||||
"urgent": 0.0,
|
||||
"apologetic": 0.0
|
||||
}
|
||||
|
||||
# Define patterns for different tones (case-insensitive)
|
||||
formal_patterns = [
|
||||
r"\bI am writing to\b",
|
||||
r"\bI would like to\b",
|
||||
r"\bplease find\b",
|
||||
r"\bregarding\b",
|
||||
r"\bpursuant to\b",
|
||||
r"\bhereby\b",
|
||||
r"\bthus\b",
|
||||
r"\btherefore\b",
|
||||
r"\bfurthermore\b",
|
||||
r"\bconsequently\b",
|
||||
r"\bnevertheless\b",
|
||||
r"\bmoreover\b",
|
||||
r"\benclosed\b", # Added common formal word
|
||||
r"\bherewith\b" # Added common formal word
|
||||
]
|
||||
|
||||
friendly_patterns = [
|
||||
r"\bhope you're well\b",
|
||||
r"\bhope this finds you well\b",
|
||||
r"\bgreat to hear\b",
|
||||
r"\blooking forward\b",
|
||||
r"\bthanks\b",
|
||||
r"\bappreciate\b",
|
||||
r"!", # Exclamation points often indicate friendly or excited tone
|
||||
r"\bexcited\b",
|
||||
r"\bgreat\b", # Common friendly adjective
|
||||
r"\bnice\b" # Common friendly adjective
|
||||
]
|
||||
|
||||
assertive_patterns = [
|
||||
r"\brequire\b",
|
||||
r"\bmust\b",
|
||||
r"\bneed\b",
|
||||
r"\bexpect\b",
|
||||
r"\bdemand\b",
|
||||
r"\binsist\b",
|
||||
r"\bimmediately\b",
|
||||
r"\baction\b", # Often used in assertive contexts
|
||||
r"\bresolution\b" # Can imply assertion
|
||||
]
|
||||
|
||||
respectful_patterns = [
|
||||
r"\brespectfully\b",
|
||||
r"\bhonored\b",
|
||||
r"\bplease\b",
|
||||
r"\bkindly\b",
|
||||
r"\bgrateful\b",
|
||||
r"\bthank you\b",
|
||||
r"\bappreciate\b",
|
||||
r"\bhumbly\b", # Added respectful word
|
||||
r"\bapologies\b" # Can show respect for impact
|
||||
]
|
||||
|
||||
urgent_patterns = [
|
||||
r"\burgent\b",
|
||||
r"\bas soon as possible\b",
|
||||
r"\bASAP\b",
|
||||
r"\bimmediately\b",
|
||||
r"\bpressing\b",
|
||||
r"\bcritical\b",
|
||||
r"\bdeadline\b",
|
||||
r"\bexpedite\b", # Added urgent word
|
||||
r"\bpromptly\b" # Added urgent word
|
||||
]
|
||||
|
||||
apologetic_patterns = [
|
||||
r"\bapologize\b",
|
||||
r"\bsorry\b",
|
||||
r"\bregret\b",
|
||||
r"\bmistake\b",
|
||||
r"\berror\b",
|
||||
r"\binconvenience\b",
|
||||
r"\bfault\b", # Added apologetic word
|
||||
r"\boversight\b" # Added apologetic word
|
||||
]
|
||||
|
||||
# Count pattern matches and update scores (arbitrary weighting)
|
||||
# A simple count multiplied by a factor acts as a basic indicator
|
||||
for pattern in formal_patterns:
|
||||
tone_scores["formal"] += len(re.findall(pattern, content, re.IGNORECASE)) * 0.2
|
||||
|
||||
for pattern in friendly_patterns:
|
||||
tone_scores["friendly"] += len(re.findall(pattern, content, re.IGNORECASE)) * 0.2
|
||||
|
||||
for pattern in assertive_patterns:
|
||||
tone_scores["assertive"] += len(re.findall(pattern, content, re.IGNORECASE)) * 0.2
|
||||
|
||||
for pattern in respectful_patterns:
|
||||
tone_scores["respectful"] += len(re.findall(pattern, content, re.IGNORECASE)) * 0.2
|
||||
|
||||
for pattern in urgent_patterns:
|
||||
tone_scores["urgent"] += len(re.findall(pattern, content, re.IGNORECASE)) * 0.2
|
||||
|
||||
for pattern in apologetic_patterns:
|
||||
tone_scores["apologetic"] += len(re.findall(pattern, content, re.IGNORECASE)) * 0.2
|
||||
|
||||
# Cap scores at 1.0 (arbitrary capping)
|
||||
# A more meaningful score might be relative frequency or use a proper model
|
||||
for tone in tone_scores:
|
||||
tone_scores[tone] = min(tone_scores[tone], 1.0)
|
||||
|
||||
return tone_scores
|
||||
|
||||
def check_formality(content: str) -> float:
|
||||
"""
|
||||
Check the formality level of a letter based on the presence of formal
|
||||
vs. informal indicators and contractions.
|
||||
|
||||
Args:
|
||||
content: The letter content to analyze.
|
||||
|
||||
Returns:
|
||||
Formality score between 0.0 (very informal) and 1.0 (very formal).
|
||||
Calculated as formal_count / (formal_count + informal_count).
|
||||
"""
|
||||
# This is a simplified version based on keyword counting.
|
||||
# More accurate formality analysis would require advanced NLP techniques.
|
||||
|
||||
# Define formal and informal indicators (case-insensitive)
|
||||
formal_indicators = [
|
||||
r"\bDear\b",
|
||||
r"\bSincerely\b",
|
||||
r"\bRegards\b",
|
||||
r"\bRespectfully\b",
|
||||
r"\bI am writing to\b",
|
||||
r"\bI would like to\b",
|
||||
r"\bplease find\b",
|
||||
r"\bregarding\b",
|
||||
r"\bpursuant to\b",
|
||||
r"\bhereby\b",
|
||||
r"\bthus\b",
|
||||
r"\btherefore\b",
|
||||
r"\bfurthermore\b",
|
||||
r"\bconsequently\b",
|
||||
r"\bnevertheless\b",
|
||||
r"\bmoreover\b",
|
||||
r"\benclosed\b",
|
||||
r"\bherewith\b",
|
||||
r"\bsincerely yours\b", # Added
|
||||
r"\bto whom it may concern\b" # Added
|
||||
]
|
||||
|
||||
informal_indicators = [
|
||||
r"\bHey\b",
|
||||
r"\bHi\b",
|
||||
r"\bWhat's up\b",
|
||||
r"\bCheers\b",
|
||||
r"\bThanks\b", # 'Thank you' is formal, 'Thanks' is informal
|
||||
r"\bTake care\b",
|
||||
r"\bSee you\b",
|
||||
r"\bLater\b",
|
||||
r"\bBye\b",
|
||||
r"\bLove\b", # As a closing
|
||||
r"\bXO\b",
|
||||
r"!+", # Multiple exclamation points
|
||||
r"\bawesome\b",
|
||||
r"\bcool\b",
|
||||
r"\bgreat\b",
|
||||
r"\bnice\b",
|
||||
r"\bbtw\b", # By the way
|
||||
r"\bimo\b", # In my opinion
|
||||
r"\blol\b" # Laugh out loud
|
||||
]
|
||||
|
||||
# Define common contractions (case-insensitive)
|
||||
contractions = [
|
||||
r"\bdon't\b", r"\bcan't\b", r"\bwon't\b", r"\bshouldn't\b",
|
||||
r"\bcouldn't\b", r"\bwouldn't\b", r"\bhasn't\b", r"\bhaven't\b",
|
||||
r"\bisn't\b", r"\baren't\b", r"\bwasn't\b", r"\bweren't\b",
|
||||
r"\bi'm\b", r"\byou're\b", r"\bhe's\b", r"\bshe's\b", r"\bit's\b",
|
||||
r"\bwe're\b", r"\bthey're\b", r"\bi've\b", r"\byou've\b",
|
||||
r"\bwe've\b", r"\bthey've\b", r"\bi'd\b", r"\byou'd\b",
|
||||
r"\bhe'd\b", r"\bshe'd\b", r"\bit'd\b", r"\bwe'd\b", r"\bthey'd\b",
|
||||
r"\bi'll\b", r"\byou'll\b", r"\bhe'll\b", r"\bshe'll\b", r"\bit'll\b",
|
||||
r"\bwe'll\b", r"\bthey'll\b"
|
||||
]
|
||||
|
||||
formal_count = 0
|
||||
for pattern in formal_indicators:
|
||||
formal_count += len(re.findall(pattern, content, re.IGNORECASE))
|
||||
|
||||
informal_count = 0
|
||||
for pattern in informal_indicators:
|
||||
informal_count += len(re.findall(pattern, content, re.IGNORECASE))
|
||||
|
||||
# Count contractions as informal indicators
|
||||
for pattern in contractions:
|
||||
informal_count += len(re.findall(pattern, content, re.IGNORECASE))
|
||||
|
||||
# Calculate formality score
|
||||
total_indicators = formal_count + informal_count
|
||||
if total_indicators == 0:
|
||||
# If no indicators found, return a neutral score
|
||||
return 0.5
|
||||
|
||||
# Score is the proportion of formal indicators
|
||||
formality_score = formal_count / total_indicators
|
||||
return formality_score
|
||||
|
||||
def count_syllables_simple(word: str) -> int:
|
||||
"""
|
||||
Counts syllables in a word using a simplified heuristic.
|
||||
This method is not linguistically perfect but provides a basic estimate
|
||||
for readability formulas.
|
||||
|
||||
Args:
|
||||
word: The word string.
|
||||
|
||||
Returns:
|
||||
Estimated syllable count.
|
||||
"""
|
||||
word = word.lower()
|
||||
if len(word) <= 3:
|
||||
# Assume short words have one syllable
|
||||
return 1
|
||||
|
||||
# Remove common silent endings like 'e', 'es', 'ed'
|
||||
if word.endswith(('es', 'ed')):
|
||||
word = word[:-2]
|
||||
elif word.endswith('e'):
|
||||
word = word[:-1]
|
||||
|
||||
# Count vowel groups (consecutive vowels count as one syllable)
|
||||
vowels = 'aeiouy'
|
||||
count = 0
|
||||
prev_is_vowel = False
|
||||
|
||||
for char in word:
|
||||
is_vowel = char in vowels
|
||||
if is_vowel and not prev_is_vowel:
|
||||
count += 1
|
||||
prev_is_vowel = is_vowel
|
||||
|
||||
# Ensure at least one syllable is counted
|
||||
return max(1, count)
|
||||
|
||||
|
||||
def get_readability_metrics(content: str) -> Dict[str, Any]:
|
||||
"""
|
||||
Calculate readability metrics for a letter using simplified methods
|
||||
like Flesch Reading Ease.
|
||||
|
||||
Args:
|
||||
content: The letter content to analyze.
|
||||
|
||||
Returns:
|
||||
Dictionary with readability metrics: word_count, sentence_count,
|
||||
avg_words_per_sentence, flesch_reading_ease, reading_level.
|
||||
"""
|
||||
# Split content into words and sentences using simple regex
|
||||
words = re.findall(r'\b\w+\b', content)
|
||||
# Split by common sentence terminators, handling potential multiple marks
|
||||
sentences = re.split(r'[.!?]+\s*', content)
|
||||
# Filter out empty strings resulting from the split (e.g., trailing punctuation)
|
||||
sentences = [s for s in sentences if s.strip()]
|
||||
|
||||
word_count = len(words)
|
||||
sentence_count = len(sentences)
|
||||
syllable_count = sum(count_syllables_simple(word) for word in words)
|
||||
|
||||
if word_count == 0 or sentence_count == 0:
|
||||
return {
|
||||
"word_count": word_count,
|
||||
"sentence_count": sentence_count,
|
||||
"avg_words_per_sentence": 0.0,
|
||||
"flesch_reading_ease": 0.0,
|
||||
"reading_level": "N/A"
|
||||
}
|
||||
|
||||
# Calculate average words per sentence
|
||||
avg_words_per_sentence = word_count / sentence_count
|
||||
|
||||
# Calculate Flesch Reading Ease Score
|
||||
# Formula: 206.835 - (1.015 * AvgWordsPerSentence) - (84.6 * AvgSyllablesPerWord)
|
||||
# AvgSyllablesPerWord = syllable_count / word_count
|
||||
avg_syllables_per_word = syllable_count / word_count if word_count > 0 else 0
|
||||
|
||||
flesch = 206.835 - (1.015 * avg_words_per_sentence) - (84.6 * avg_syllables_per_word)
|
||||
# Clamp score between 0 and 100
|
||||
flesch = max(0.0, min(100.0, flesch))
|
||||
|
||||
# Determine reading level based on Flesch score ranges
|
||||
if flesch >= 90:
|
||||
reading_level = "Very Easy (5th grade)"
|
||||
elif flesch >= 80:
|
||||
reading_level = "Easy (6th grade)"
|
||||
elif flesch >= 70:
|
||||
reading_level = "Fairly Easy (7th grade)"
|
||||
elif flesch >= 60:
|
||||
reading_level = "Standard (8th-9th grade)"
|
||||
elif flesch >= 50:
|
||||
reading_level = "Fairly Difficult (10th-12th grade)"
|
||||
elif flesch >= 30:
|
||||
reading_level = "Difficult (College)"
|
||||
else:
|
||||
reading_level = "Very Difficult (Graduate)"
|
||||
|
||||
return {
|
||||
"word_count": word_count,
|
||||
"sentence_count": sentence_count,
|
||||
"avg_words_per_sentence": round(avg_words_per_sentence, 2), # Rounded for display
|
||||
"flesch_reading_ease": round(flesch, 2), # Rounded for display
|
||||
"reading_level": reading_level
|
||||
}
|
||||
|
||||
def suggest_improvements(content: str, letter_type: str) -> List[str]:
|
||||
"""
|
||||
Suggest improvements for a letter based on its content, basic analysis,
|
||||
and target letter type.
|
||||
|
||||
Args:
|
||||
content: The letter content to analyze.
|
||||
letter_type: The type of letter (e.g., "business", "cover", "personal").
|
||||
|
||||
Returns:
|
||||
List of improvement suggestions strings.
|
||||
"""
|
||||
suggestions = []
|
||||
|
||||
words = re.findall(r'\b\w+\b', content)
|
||||
word_count = len(words)
|
||||
|
||||
# Basic length check based on letter type
|
||||
if letter_type in ["business", "formal"]:
|
||||
if word_count < 100 and word_count > 10: # Avoid suggesting for very short placeholders
|
||||
suggestions.append("Consider adding more details to make your letter more comprehensive.")
|
||||
elif word_count > 600: # Increased max length slightly
|
||||
suggestions.append("Your letter is quite long. Consider condensing it for better readability and focus.")
|
||||
elif letter_type == "cover":
|
||||
if word_count < 150 and word_count > 10: # Avoid suggesting for very short placeholders
|
||||
suggestions.append("Your cover letter may be too brief. Consider highlighting more of your relevant qualifications.")
|
||||
elif word_count > 500: # Increased max length slightly
|
||||
suggestions.append("Your cover letter is quite long. Consider focusing on your most relevant qualifications and experiences.")
|
||||
elif letter_type == "recommendation":
|
||||
if word_count < 150 and word_count > 10:
|
||||
suggestions.append("Consider adding more specific examples or anecdotes to strengthen the recommendation.")
|
||||
elif word_count > 600:
|
||||
suggestions.append("Your recommendation letter is quite long. Ensure it remains focused and impactful.")
|
||||
|
||||
|
||||
# Check for overuse of "I" (simple count-based heuristic)
|
||||
# Count "I" as a standalone word
|
||||
i_count = len(re.findall(r"\bI\b", content))
|
||||
# Avoid suggestion for very short content or content with few sentences
|
||||
sentence_count = len(re.split(r'[.!?]+\s*', content.strip()))
|
||||
if sentence_count > 2 and word_count > 50 and i_count > sentence_count * 1.5: # Suggest if 'I' count is significantly higher than sentence count
|
||||
suggestions.append("Your letter contains many uses of 'I'. Consider rephrasing some sentences to focus more on the recipient or the subject matter.")
|
||||
|
||||
|
||||
# Check for expression of gratitude (using common phrases)
|
||||
gratitude_patterns = [r"\bthank you\b", r"\bgrateful\b", r"\bappreciate\b"]
|
||||
has_gratitude = any(re.search(pattern, content, re.IGNORECASE) for pattern in gratitude_patterns)
|
||||
# Suggest adding gratitude, but avoid for letter types where it might be less common (e.g., some complaint letters)
|
||||
if not has_gratitude and letter_type not in ["complaint", "urgent"]:
|
||||
suggestions.append("Consider expressing gratitude or appreciation somewhere in your letter.")
|
||||
|
||||
# Check for clear call to action (using common phrases)
|
||||
# Phrases indicating desired action or next step
|
||||
action_phrases = [
|
||||
"look forward to", "please", "would appreciate", "request",
|
||||
"hope to", "call me", "email me", "contact me", "schedule",
|
||||
"arrange", "require action", "next steps"
|
||||
]
|
||||
has_call_to_action = any(phrase in content.lower() for phrase in action_phrases)
|
||||
# Suggest adding a call to action for relevant letter types
|
||||
if not has_call_to_action and letter_type in ["business", "cover", "complaint", "invitation"]:
|
||||
suggestions.append("Consider adding a clear call to action or outlining the desired next steps.")
|
||||
|
||||
# Check for proper closing (using common phrases)
|
||||
closing_patterns = [
|
||||
r"\bSincerely\b", r"\bRegards\b", r"\bThank you\b", r"\bBest regards\b",
|
||||
r"\bYours sincerely\b", r"\bYours faithfully\b", r"\bRespectfully\b",
|
||||
r"\bBest wishes\b", r"\bKind regards\b"
|
||||
]
|
||||
# Check if any standard closing phrase is present, typically near the end
|
||||
# A more robust check might look specifically at the last paragraph/lines
|
||||
has_proper_closing = any(re.search(pattern, content[-200:], re.IGNORECASE) for pattern in closing_patterns) # Check last 200 chars
|
||||
|
||||
if not has_proper_closing and word_count > 20: # Avoid suggesting for very short snippets
|
||||
suggestions.append("Consider adding a proper closing phrase (e.g., Sincerely, Regards) followed by your name.")
|
||||
|
||||
return suggestions
|
||||
|
||||
# Example usage (for testing purposes, not part of the module's core functionality)
|
||||
if __name__ == '__main__':
|
||||
sample_formal_letter = """
|
||||
Dear Mr. Smith,
|
||||
|
||||
I am writing to follow up regarding the project proposal submitted on October 26, 2023.
|
||||
We believe the proposed solution aligns well with your stated requirements.
|
||||
Please find the revised budget document attached for your review.
|
||||
We look forward to your feedback at your earliest convenience.
|
||||
|
||||
Sincerely,
|
||||
Jane Doe
|
||||
"""
|
||||
|
||||
sample_informal_letter = """
|
||||
Hey John,
|
||||
|
||||
Hope you're doing well! Just wanted to quickly touch base about the party next week.
|
||||
Excited to catch up with everyone! Let me know if you need any help setting up.
|
||||
Thanks!
|
||||
|
||||
Best,
|
||||
Alex
|
||||
"""
|
||||
|
||||
sample_complaint_letter = """
|
||||
To Whom It May Concern,
|
||||
|
||||
I am writing to complain about the faulty product I received on November 1, 2023 (Order #12345).
|
||||
The device stopped working after only two days of use. I require a full refund or replacement immediately.
|
||||
I expect a prompt response regarding this issue.
|
||||
|
||||
Sincerely,
|
||||
Concerned Customer
|
||||
"""
|
||||
|
||||
print("--- Analyzing Formal Letter ---")
|
||||
tone = analyze_letter_tone(sample_formal_letter)
|
||||
formality = check_formality(sample_formal_letter)
|
||||
readability = get_readability_metrics(sample_formal_letter)
|
||||
suggestions = suggest_improvements(sample_formal_letter, "business")
|
||||
|
||||
print(f"Tone: {tone}")
|
||||
print(f"Formality: {formality:.2f}")
|
||||
print(f"Readability: {readability}")
|
||||
print(f"Suggestions: {suggestions}")
|
||||
|
||||
print("\n--- Analyzing Informal Letter ---")
|
||||
tone = analyze_letter_tone(sample_informal_letter)
|
||||
formality = check_formality(sample_informal_letter)
|
||||
readability = get_readability_metrics(sample_informal_letter)
|
||||
suggestions = suggest_improvements(sample_informal_letter, "personal")
|
||||
|
||||
print(f"Tone: {tone}")
|
||||
print(f"Formality: {formality:.2f}")
|
||||
print(f"Readability: {readability}")
|
||||
print(f"Suggestions: {suggestions}")
|
||||
|
||||
print("\n--- Analyzing Complaint Letter ---")
|
||||
tone = analyze_letter_tone(sample_complaint_letter)
|
||||
formality = check_formality(sample_complaint_letter)
|
||||
readability = get_readability_metrics(sample_complaint_letter)
|
||||
suggestions = suggest_improvements(sample_complaint_letter, "complaint")
|
||||
|
||||
print(f"Tone: {tone}")
|
||||
print(f"Formality: {formality:.2f}")
|
||||
print(f"Readability: {readability}")
|
||||
print(f"Suggestions: {suggestions}")
|
||||
545
lib/ai_writers/ai_letter_writer/utils/letter_formatter.py
Normal file
545
lib/ai_writers/ai_letter_writer/utils/letter_formatter.py
Normal file
@@ -0,0 +1,545 @@
|
||||
"""
|
||||
Letter Formatter Module
|
||||
|
||||
This module provides utilities for formatting letters and generating HTML
|
||||
previews in different styles (Personal, Formal, Business, Cover).
|
||||
The formatting functions here are primarily focused on generating HTML
|
||||
for preview purposes, applying standard layout conventions for each letter type
|
||||
using inline CSS styles.
|
||||
"""
|
||||
|
||||
import re
|
||||
from typing import Dict, Any
|
||||
|
||||
def format_letter(content: str, metadata: Dict[str, Any], letter_type: str = "personal") -> str:
|
||||
"""
|
||||
Format a letter with basic structure (paragraphs).
|
||||
|
||||
Args:
|
||||
content: The raw letter content (string).
|
||||
metadata: Dictionary containing metadata (currently not used for formatting in this placeholder).
|
||||
letter_type: Type of letter (personal, formal, business, cover).
|
||||
|
||||
Returns:
|
||||
Formatted letter content (currently just returns the input content).
|
||||
This is a placeholder and would be expanded to apply specific
|
||||
formatting rules (e.g., indentation, spacing) based on letter type
|
||||
and metadata in a full implementation before generating HTML.
|
||||
For this module, we primarily rely on the HTML generation functions
|
||||
to handle the visual formatting.
|
||||
"""
|
||||
# This is a basic placeholder. In a real implementation, this function
|
||||
# might process the raw text content to add indentation, adjust line breaks,
|
||||
# or handle specific markdown-like syntax before it's passed to the
|
||||
# HTML generation functions.
|
||||
# For now, we assume the input `content` uses double newlines for paragraphs.
|
||||
return content
|
||||
|
||||
def get_letter_preview_html(content: str, metadata: Dict[str, Any], letter_type: str = "personal") -> str:
|
||||
"""
|
||||
Generate HTML for letter preview based on letter type and metadata.
|
||||
This function acts as a dispatcher to the specific HTML generation functions.
|
||||
|
||||
Args:
|
||||
content: The letter content string.
|
||||
metadata: Dictionary containing metadata like sender/recipient info, date, etc.
|
||||
letter_type: Type of letter ("personal", "formal", "business", "cover").
|
||||
Defaults to "personal".
|
||||
|
||||
Returns:
|
||||
HTML string for letter preview, styled appropriately for the type.
|
||||
Includes basic styling for a printable letter appearance.
|
||||
"""
|
||||
# Dispatch to the appropriate HTML generation function based on letter type
|
||||
# Pass the content and metadata to the specific functions
|
||||
if letter_type == "personal":
|
||||
return get_personal_letter_html(content, metadata)
|
||||
elif letter_type == "formal":
|
||||
return get_formal_letter_html(content, metadata)
|
||||
elif letter_type == "business":
|
||||
return get_business_letter_html(content, metadata)
|
||||
elif letter_type == "cover":
|
||||
return get_cover_letter_html(content, metadata)
|
||||
else:
|
||||
# Fallback for unrecognized types, displaying raw content in a styled box
|
||||
return f"""
|
||||
<div style="max-width: 800px; margin: 20px auto; padding: 20px; border: 1px solid #ccc; font-family: sans-serif; line-height: 1.6; background-color: #fff8f8; color: #333; border-radius: 8px;">
|
||||
<h3 style="color: #e53935; margin-top: 0;">Preview Unavailable for Unknown Letter Type</h3>
|
||||
<p>The letter type '{letter_type}' is not recognized. Displaying raw content:</p>
|
||||
<pre style="white-space: pre-wrap; word-wrap: break-word; background-color: #f8f8f8; padding: 15px; border: 1px solid #ddd; border-radius: 4px; overflow-x: auto;">{content}</pre>
|
||||
</div>
|
||||
"""
|
||||
|
||||
def get_personal_letter_html(content: str, metadata: Dict[str, Any]) -> str:
|
||||
"""
|
||||
Generate HTML for personal letter preview with basic styling.
|
||||
Uses a more informal layout and font style.
|
||||
|
||||
Args:
|
||||
content: The letter content string.
|
||||
metadata: Dictionary containing personal letter metadata (sender_name, date).
|
||||
|
||||
Returns:
|
||||
HTML string for personal letter preview.
|
||||
"""
|
||||
# Extract metadata with default empty strings for robustness
|
||||
sender_name = metadata.get("sender_name", "")
|
||||
# recipient_name = metadata.get("recipient_name", "") # Less common in personal body, but could be used in greeting
|
||||
date = metadata.get("date", "")
|
||||
|
||||
# Split content into paragraphs based on double newlines
|
||||
# Use list comprehension to strip whitespace and filter out empty strings
|
||||
paragraphs = [p.strip() for p in content.split("\n\n") if p.strip()]
|
||||
|
||||
# Format paragraphs as HTML <p> tags with bottom margin
|
||||
formatted_paragraphs = "".join(f"<p style='margin-bottom: 1em;'>{paragraph}</p>" for paragraph in paragraphs)
|
||||
|
||||
# Basic HTML structure with inline styles for a personal letter feel
|
||||
# Styles aim for a warm, readable appearance
|
||||
html = f"""
|
||||
<div style="max-width: 700px; margin: 20px auto; padding: 30px; border: 1px solid #e0e0e0; border-radius: 8px; background-color: #ffffff; font-family: 'Georgia', serif; line-height: 1.7; color: #333; box-shadow: 0 2px 4px rgba(0,0,0,0.1);">
|
||||
<div style="text-align: right; margin-bottom: 30px; font-size: 0.9em; color: #555;">
|
||||
{date if date else "[Date]"}
|
||||
</div>
|
||||
|
||||
<div style="margin-bottom: 30px;">
|
||||
{formatted_paragraphs if formatted_paragraphs else "<p style='color: #888;'>Letter content goes here...</p>"}
|
||||
</div>
|
||||
|
||||
<div style="margin-top: 40px;">
|
||||
<p style="margin-bottom: 0.5em;">Sincerely,</p>
|
||||
<p style="font-weight: bold; margin-top: 0;">{sender_name if sender_name else "[Sender Name]"}</p>
|
||||
</div>
|
||||
</div>
|
||||
"""
|
||||
return html
|
||||
|
||||
def get_formal_letter_html(content: str, metadata: Dict[str, Any]) -> str:
|
||||
"""
|
||||
Generate HTML for formal letter preview with standard formal structure and styling.
|
||||
Uses a more professional layout and font style (Arial/sans-serif).
|
||||
|
||||
Args:
|
||||
content: The letter content string.
|
||||
metadata: Dictionary containing formal letter metadata.
|
||||
|
||||
Returns:
|
||||
HTML string for formal letter preview.
|
||||
"""
|
||||
# Extract metadata with default empty strings
|
||||
sender_name = metadata.get("sender_name", "")
|
||||
sender_title = metadata.get("sender_title", "")
|
||||
sender_organization = metadata.get("sender_organization", "")
|
||||
# Replace newlines in address for HTML display
|
||||
sender_address = metadata.get("sender_address", "").replace("\n", "<br>")
|
||||
sender_phone = metadata.get("sender_phone", "")
|
||||
sender_email = metadata.get("sender_email", "")
|
||||
|
||||
recipient_name = metadata.get("recipient_name", "")
|
||||
recipient_title = metadata.get("recipient_title", "")
|
||||
recipient_organization = metadata.get("recipient_organization", "")
|
||||
# Replace newlines in address for HTML display
|
||||
recipient_address = metadata.get("recipient_address", "").replace("\n", "<br>")
|
||||
|
||||
date = metadata.get("date", "")
|
||||
subject = metadata.get("subject", "") # Added subject line
|
||||
salutation = metadata.get("salutation", "Dear Sir/Madam,") # Added salutation
|
||||
complimentary_close = metadata.get("complimentary_close", "Sincerely,") # Added close
|
||||
|
||||
# Determine alignment based on letter format (simplified)
|
||||
# Full Block: All aligned left
|
||||
# Modified Block: Sender address block, date, closing, and signature are right-aligned
|
||||
letter_format = metadata.get("letter_format", "Full Block")
|
||||
sender_address_align = "left"
|
||||
date_align = "left"
|
||||
closing_align = "left"
|
||||
|
||||
if letter_format == "Modified Block":
|
||||
sender_address_align = "right"
|
||||
date_align = "right"
|
||||
closing_align = "right"
|
||||
|
||||
# Split content into paragraphs based on double newlines
|
||||
paragraphs = [p.strip() for p in content.split("\n\n") if p.strip()]
|
||||
|
||||
# Format paragraphs as HTML <p> tags with bottom margin
|
||||
formatted_paragraphs = "".join(f"<p style='margin-bottom: 1em;'>{paragraph}</p>" for paragraph in paragraphs)
|
||||
|
||||
# Basic HTML structure with inline styles for a formal letter
|
||||
html = f"""
|
||||
<div style="max-width: 800px; margin: 20px auto; padding: 30px; border: 1px solid #d0d0d0; border-radius: 8px; background-color: #ffffff; font-family: 'Arial', sans-serif; line-height: 1.6; color: #333; box-shadow: 0 2px 4px rgba(0,0,0,0.1);">
|
||||
|
||||
<div style="text-align: {sender_address_align}; margin-bottom: 20px; font-size: 0.9em;">
|
||||
<p style="margin: 0;">{sender_name if sender_name else "[Sender Name]"}{', ' + sender_title if sender_title else ''}</p>
|
||||
<p style="margin: 0;">{sender_organization if sender_organization else "[Sender Organization]"}</p>
|
||||
<p style="margin: 0;">{sender_address if sender_address else "[Sender Address]"}</p>
|
||||
<p style="margin: 0;">{sender_phone}</p>
|
||||
<p style="margin: 0;">{sender_email}</p>
|
||||
</div>
|
||||
|
||||
<div style="text-align: {date_align}; margin-bottom: 20px;">
|
||||
<p style="margin: 0;">{date if date else "[Date]"}</p>
|
||||
</div>
|
||||
|
||||
<div style="margin-bottom: 20px; font-size: 0.9em;">
|
||||
<p style="margin: 0;">{recipient_name if recipient_name else "[Recipient Name]"}{', ' + recipient_title if recipient_title else ''}</p>
|
||||
<p style="margin: 0;">{recipient_organization if recipient_organization else "[Recipient Organization]"}</p>
|
||||
<p style="margin: 0;">{recipient_address if recipient_address else "[Recipient Address]"}</p>
|
||||
</div>
|
||||
|
||||
<div style="margin-bottom: 20px;">
|
||||
<p style="margin: 0; font-weight: bold;">Subject: {subject if subject else "[Subject Line]"}</p>
|
||||
</div>
|
||||
|
||||
<div style="margin-bottom: 20px;">
|
||||
<p style="margin: 0;">{salutation}</p>
|
||||
</div>
|
||||
|
||||
<div style="margin-bottom: 20px;">
|
||||
{formatted_paragraphs if formatted_paragraphs else "<p style='color: #888;'>Letter content goes here...</p>"}
|
||||
</div>
|
||||
|
||||
<div style="margin-top: 40px; text-align: {closing_align};">
|
||||
<p style="margin-bottom: 0.5em;">{complimentary_close}</p>
|
||||
<p style="font-weight: bold; margin: 0;">{sender_name}</p>
|
||||
<p style="margin: 0; font-size: 0.9em;">{sender_title}</p>
|
||||
<p style="margin: 0; font-size: 0.9em;">{sender_organization}</p>
|
||||
</div>
|
||||
</div>
|
||||
"""
|
||||
return html
|
||||
|
||||
def get_business_letter_html(content: str, metadata: Dict[str, Any]) -> str:
|
||||
"""
|
||||
Generate HTML for business letter preview with standard business structure and styling.
|
||||
Includes optional letterhead.
|
||||
|
||||
Args:
|
||||
content: The letter content string.
|
||||
metadata: Dictionary containing business letter metadata.
|
||||
|
||||
Returns:
|
||||
HTML string for business letter preview.
|
||||
"""
|
||||
# Extract metadata with default empty strings
|
||||
sender_company = metadata.get("sender_company", "")
|
||||
sender_name = metadata.get("sender_name", "")
|
||||
sender_title = metadata.get("sender_title", "")
|
||||
sender_address = metadata.get("sender_address", "").replace("\n", "<br>")
|
||||
sender_phone = metadata.get("sender_phone", "")
|
||||
sender_email = metadata.get("sender_email", "")
|
||||
sender_website = metadata.get("sender_website", "")
|
||||
|
||||
recipient_company = metadata.get("recipient_company", "")
|
||||
recipient_name = metadata.get("recipient_name", "")
|
||||
recipient_title = metadata.get("recipient_title", "")
|
||||
recipient_address = metadata.get("recipient_address", "").replace("\n", "<br>")
|
||||
|
||||
date = metadata.get("date", "")
|
||||
subject = metadata.get("subject", "") # Added subject line
|
||||
salutation = metadata.get("salutation", "Dear Sir/Madam,") # Added salutation
|
||||
complimentary_close = metadata.get("complimentary_close", "Sincerely,") # Added close
|
||||
|
||||
# Determine alignment based on letter format (simplified)
|
||||
letter_format = metadata.get("letter_format", "Full Block")
|
||||
sender_info_align = "left"
|
||||
date_align = "left"
|
||||
closing_align = "left"
|
||||
|
||||
if letter_format == "Modified Block":
|
||||
sender_info_align = "right"
|
||||
date_align = "right"
|
||||
closing_align = "right"
|
||||
|
||||
# Include letterhead logic
|
||||
include_letterhead = metadata.get("include_letterhead", True)
|
||||
|
||||
# Split content into paragraphs based on double newlines
|
||||
paragraphs = [p.strip() for p in content.split("\n\n") if p.strip()]
|
||||
|
||||
# Format paragraphs as HTML <p> tags with bottom margin
|
||||
formatted_paragraphs = "".join(f"<p style='margin-bottom: 1em;'>{paragraph}</p>" for paragraph in paragraphs)
|
||||
|
||||
# Create letterhead HTML if included and company name is provided
|
||||
letterhead_html = ""
|
||||
if include_letterhead and sender_company:
|
||||
letterhead_html = f"""
|
||||
<div style="padding-bottom: 15px; margin-bottom: 20px; border-bottom: 1px solid #eee;">
|
||||
<h2 style="margin: 0; color: #333; font-size: 1.5em;">{sender_company}</h2>
|
||||
<p style="margin: 5px 0 0 0; font-size: 0.9em; color: #555;">
|
||||
{sender_address.replace('<br>', ', ') if sender_address else ''}
|
||||
{' | ' + sender_phone if sender_phone else ''}
|
||||
{' | ' + sender_email if sender_email else ''}
|
||||
{' | ' + sender_website if sender_website else ''}
|
||||
</p>
|
||||
</div>
|
||||
"""
|
||||
|
||||
# Basic HTML structure with inline styles for a business letter
|
||||
html = f"""
|
||||
<div style="max-width: 800px; margin: 20px auto; padding: 30px; border: 1px solid #d0d0d0; border-radius: 8px; background-color: #ffffff; font-family: 'Arial', sans-serif; line-height: 1.6; color: #333; box-shadow: 0 2px 4px rgba(0,0,0,0.1);">
|
||||
{letterhead_html}
|
||||
|
||||
<div style="text-align: {date_align}; margin-bottom: 20px;">
|
||||
<p style="margin: 0;">{date if date else "[Date]"}</p>
|
||||
</div>
|
||||
|
||||
<div style="margin-bottom: 20px; font-size: 0.9em;">
|
||||
<p style="margin: 0;">{recipient_name if recipient_name else "[Recipient Name]"}{', ' + recipient_title if recipient_title else ''}</p>
|
||||
<p style="margin: 0;">{recipient_company if recipient_company else "[Recipient Company]"}</p>
|
||||
<p style="margin: 0;">{recipient_address if recipient_address else "[Recipient Address]"}</p>
|
||||
</div>
|
||||
|
||||
<div style="margin-bottom: 20px;">
|
||||
<p style="margin: 0; font-weight: bold;">Subject: {subject if subject else "[Subject Line]"}</p>
|
||||
</div>
|
||||
|
||||
<div style="margin-bottom: 20px;">
|
||||
<p style="margin: 0;">{salutation}</p>
|
||||
</div>
|
||||
|
||||
<div style="margin-bottom: 20px;">
|
||||
{formatted_paragraphs if formatted_paragraphs else "<p style='color: #888;'>Letter content goes here...</p>"}
|
||||
</div>
|
||||
|
||||
<div style="margin-top: 40px; text-align: {closing_align};">
|
||||
<p style="margin-bottom: 0.5em;">{complimentary_close}</p>
|
||||
<p style="font-weight: bold; margin: 0;">{sender_name if sender_name else "[Sender Name]"}</p>
|
||||
<p style="margin: 0; font-size: 0.9em;">{sender_title}</p>
|
||||
<p style="margin: 0; font-size: 0.9em;">{sender_company}</p>
|
||||
</div>
|
||||
</div>
|
||||
"""
|
||||
return html
|
||||
|
||||
def get_cover_letter_html(content: str, metadata: Dict[str, Any]) -> str:
|
||||
"""
|
||||
Generate HTML for cover letter preview with standard cover letter structure and styling.
|
||||
Includes sender contact block and optional online links.
|
||||
|
||||
Args:
|
||||
content: The letter content string.
|
||||
metadata: Dictionary containing cover letter metadata.
|
||||
|
||||
Returns:
|
||||
HTML string for cover letter preview.
|
||||
"""
|
||||
# Extract metadata with default empty strings
|
||||
sender_name = metadata.get("sender_name", "")
|
||||
sender_email = metadata.get("sender_email", "")
|
||||
sender_phone = metadata.get("sender_phone", "")
|
||||
sender_location = metadata.get("sender_location", "")
|
||||
sender_linkedin = metadata.get("sender_linkedin", "")
|
||||
sender_portfolio = metadata.get("sender_portfolio", "")
|
||||
|
||||
recipient_name = metadata.get("recipient_name", "")
|
||||
recipient_title = metadata.get("recipient_title", "") # Added recipient title
|
||||
recipient_company = metadata.get("recipient_company", "")
|
||||
recipient_department = metadata.get("recipient_department", "") # Added department
|
||||
recipient_address = metadata.get("recipient_address", "").replace("\n", "<br>") # Added recipient address
|
||||
|
||||
date = metadata.get("date", "")
|
||||
job_title = metadata.get("job_title", "") # Added job title for subject
|
||||
salutation = metadata.get("salutation", "Dear Hiring Manager,") # Added salutation
|
||||
complimentary_close = metadata.get("complimentary_close", "Sincerely,") # Added close
|
||||
|
||||
|
||||
# Split content into paragraphs based on double newlines
|
||||
paragraphs = [p.strip() for p in content.split("\n\n") if p.strip()]
|
||||
|
||||
# Format paragraphs as HTML <p> tags with bottom margin
|
||||
formatted_paragraphs = "".join(f"<p style='margin-bottom: 1em;'>{paragraph}</p>" for paragraph in paragraphs)
|
||||
|
||||
# Construct sender contact line, only including fields that have values
|
||||
sender_contact_parts = [sender_location, sender_phone, sender_email]
|
||||
sender_contact_line = " | ".join(filter(None, sender_contact_parts))
|
||||
|
||||
# Construct sender online links line, only including fields that have values
|
||||
sender_online_parts = []
|
||||
if sender_linkedin:
|
||||
# Add basic styling for links
|
||||
sender_online_parts.append(f'<a href="{sender_linkedin}" style="color: #0077b5; text-decoration: none;">LinkedIn</a>')
|
||||
if sender_portfolio:
|
||||
# Add basic styling for links
|
||||
sender_online_parts.append(f'<a href="{sender_portfolio}" style="color: #0077b5; text-decoration: none;">Portfolio</a>')
|
||||
|
||||
sender_online_line = " | ".join(filter(None, sender_online_parts))
|
||||
|
||||
|
||||
# Basic HTML structure with inline styles for a cover letter
|
||||
# Styles aim for a clean, professional look
|
||||
html = f"""
|
||||
<div style="max-width: 800px; margin: 20px auto; padding: 30px; border: 1px solid #d0d0d0; border-radius: 8px; background-color: #ffffff; font-family: 'Arial', sans-serif; line-height: 1.6; color: #333; box-shadow: 0 2px 4px rgba(0,0,0,0.1);">
|
||||
|
||||
<div style="text-align: left; margin-bottom: 30px; padding-bottom: 15px; border-bottom: 1px solid #eee;">
|
||||
<h2 style="margin: 0; color: #333; font-size: 1.5em;">{sender_name if sender_name else "[Your Name]"}</h2>
|
||||
{'<p style="margin: 5px 0 0 0; font-size: 0.9em; color: #555;">' + sender_contact_line + '</p>' if sender_contact_line else ''}
|
||||
{'<p style="margin: 2px 0 0 0; font-size: 0.9em;">' + sender_online_line + '</p>' if sender_online_line else ''}
|
||||
</div>
|
||||
|
||||
<div style="margin-bottom: 20px;">
|
||||
<p style="margin: 0;">{date if date else "[Date]"}</p>
|
||||
</div>
|
||||
|
||||
<div style="margin-bottom: 20px; font-size: 0.9em;">
|
||||
<p style="margin: 0;">{recipient_name if recipient_name else "[Recipient Name]"}{', ' + recipient_title if recipient_title else ''}</p>
|
||||
<p style="margin: 0;">{recipient_department}</p>
|
||||
<p style="margin: 0;">{recipient_company if recipient_company else "[Recipient Company]"}</p>
|
||||
<p style="margin: 0;">{recipient_address if recipient_address else "[Recipient Address]"}</p>
|
||||
</div>
|
||||
|
||||
<div style="margin-bottom: 20px;">
|
||||
<p style="margin: 0; font-weight: bold;">Subject: Application for {job_title if job_title else '[Job Title]'} Position</p>
|
||||
</div>
|
||||
|
||||
<div style="margin-bottom: 20px;">
|
||||
<p style="margin: 0;">{salutation}</p>
|
||||
</div>
|
||||
|
||||
<div style="margin-bottom: 20px;">
|
||||
{formatted_paragraphs if formatted_paragraphs else "<p style='color: #888;'>Letter content goes here...</p>"}
|
||||
</div>
|
||||
|
||||
<div style="margin-top: 40px;">
|
||||
<p style="margin-bottom: 0.5em;">{complimentary_close}</p>
|
||||
<p style="font-weight: bold; margin: 0;">{sender_name}</p>
|
||||
</div>
|
||||
</div>
|
||||
"""
|
||||
return html
|
||||
|
||||
# Example usage (for testing purposes)
|
||||
if __name__ == '__main__':
|
||||
sample_personal_content = """
|
||||
Hi Sarah,
|
||||
|
||||
Hope you're doing well!
|
||||
|
||||
Just wanted to send a quick note to say how much I enjoyed catching up last week. It was great hearing about your trip to Italy.
|
||||
|
||||
Let's try to do it again soon!
|
||||
|
||||
Best,
|
||||
Emily
|
||||
"""
|
||||
sample_personal_metadata = {
|
||||
"sender_name": "Emily Davis",
|
||||
"recipient_name": "Sarah Johnson",
|
||||
"date": "November 5, 2023"
|
||||
}
|
||||
|
||||
sample_formal_content = """
|
||||
I am writing to formally request a copy of my academic transcript.
|
||||
|
||||
I require this document for a graduate school application. The deadline for submission is December 15, 2023.
|
||||
|
||||
Please let me know if there are any fees associated with this request or if any further information is needed from my end.
|
||||
|
||||
Thank you for your time and assistance.
|
||||
"""
|
||||
sample_formal_metadata_full_block = {
|
||||
"sender_name": "John Smith",
|
||||
"sender_title": "Student",
|
||||
"sender_organization": "University of Example",
|
||||
"sender_address": "123 University Ave\nAnytown, CA 91234",
|
||||
"sender_phone": "(555) 123-4567",
|
||||
"sender_email": "john.smith@example.com",
|
||||
"recipient_name": "Registrar's Office",
|
||||
"recipient_organization": "University of Example",
|
||||
"recipient_address": "456 Admin Building\nAnytown, CA 91234",
|
||||
"date": "November 5, 2023",
|
||||
"subject": "Request for Academic Transcript",
|
||||
"salutation": "To the Registrar's Office,",
|
||||
"complimentary_close": "Sincerely,",
|
||||
"letter_format": "Full Block"
|
||||
}
|
||||
|
||||
sample_formal_metadata_modified_block = sample_formal_metadata_full_block.copy()
|
||||
sample_formal_metadata_modified_block["letter_format"] = "Modified Block"
|
||||
|
||||
|
||||
sample_business_content = """
|
||||
This letter confirms the details of Purchase Order #PO-7890.
|
||||
|
||||
We are ordering 50 units of Model X widgets at the agreed-upon price of $100 per unit, totaling $5,000.
|
||||
|
||||
Please ensure delivery to our warehouse by November 20, 2023. Payment will be made within 30 days of receipt of invoice.
|
||||
|
||||
Thank you for your prompt processing of this order.
|
||||
"""
|
||||
sample_business_metadata_full_block = {
|
||||
"sender_company": "Acme Corp",
|
||||
"sender_name": "Alice Brown",
|
||||
"sender_title": "Procurement Manager",
|
||||
"sender_address": "789 Business Rd\nMetropolis, NY 10001",
|
||||
"sender_phone": "(555) 987-6543",
|
||||
"sender_email": "alice.brown@acmecorp.com",
|
||||
"sender_website": "www.acmecorp.com",
|
||||
"recipient_company": "Supplier Co.",
|
||||
"recipient_name": "Sales Department",
|
||||
"recipient_title": "",
|
||||
"recipient_address": "101 Vendor Lane\nIndustriatown, TX 75001",
|
||||
"date": "November 5, 2023",
|
||||
"subject": "Purchase Order Confirmation - PO-7890",
|
||||
"salutation": "To the Sales Department,",
|
||||
"complimentary_close": "Sincerely,",
|
||||
"letter_format": "Full Block",
|
||||
"include_letterhead": True
|
||||
}
|
||||
|
||||
sample_business_metadata_modified_block = sample_business_metadata_full_block.copy()
|
||||
sample_business_metadata_modified_block["letter_format"] = "Modified Block"
|
||||
sample_business_metadata_no_letterhead = sample_business_metadata_full_block.copy()
|
||||
sample_business_metadata_no_letterhead["include_letterhead"] = False
|
||||
|
||||
|
||||
sample_cover_letter_content = """
|
||||
I am writing to express my enthusiastic interest in the Marketing Specialist position advertised on LinkedIn.
|
||||
|
||||
With three years of experience in digital marketing and a proven track record in content creation and social media management, I am confident in my ability to contribute to your team. My skills in [Specific Skill 1] and [Specific Skill 2] align perfectly with the requirements outlined in the job description.
|
||||
|
||||
In my previous role at [Previous Company], I successfully managed social media campaigns that resulted in a 25% increase in engagement. I am particularly drawn to [Company Name]'s innovative approach to [Industry Trend] and believe my creative problem-solving skills would be a valuable asset.
|
||||
|
||||
Thank you for considering my application. I have attached my resume for your review and welcome the opportunity to discuss how my background and skills can benefit [Company Name].
|
||||
"""
|
||||
sample_cover_letter_metadata = {
|
||||
"sender_name": "Jane Doe",
|
||||
"sender_email": "jane.doe@email.com",
|
||||
"sender_phone": "(123) 456-7890",
|
||||
"sender_location": "San Francisco, CA",
|
||||
"sender_linkedin": "https://linkedin.com/in/janedoe",
|
||||
"sender_portfolio": "https://janedoeportfolio.com",
|
||||
"recipient_name": "Hiring Manager",
|
||||
"recipient_title": "", # Example with no recipient title
|
||||
"recipient_company": "Innovative Solutions Inc.",
|
||||
"recipient_department": "Marketing Department",
|
||||
"recipient_address": "456 Tech Way\nSilicon Valley, CA 95001",
|
||||
"date": "November 5, 2023",
|
||||
"job_title": "Marketing Specialist",
|
||||
"salutation": "Dear Hiring Manager,",
|
||||
"complimentary_close": "Sincerely,"
|
||||
}
|
||||
|
||||
print("--- Personal Letter HTML Preview ---")
|
||||
print(get_letter_preview_html(sample_personal_content, sample_personal_metadata, letter_type="personal"))
|
||||
|
||||
print("\n--- Formal Letter HTML Preview (Full Block) ---")
|
||||
print(get_letter_preview_html(sample_formal_content, sample_formal_metadata_full_block, letter_type="formal"))
|
||||
|
||||
print("\n--- Formal Letter HTML Preview (Modified Block) ---")
|
||||
print(get_letter_preview_html(sample_formal_content, sample_formal_metadata_modified_block, letter_type="formal"))
|
||||
|
||||
print("\n--- Business Letter HTML Preview (Full Block, with Letterhead) ---")
|
||||
print(get_letter_preview_html(sample_business_content, sample_business_metadata_full_block, letter_type="business"))
|
||||
|
||||
print("\n--- Business Letter HTML Preview (Modified Block, with Letterhead) ---")
|
||||
print(get_letter_preview_html(sample_business_content, sample_business_metadata_modified_block, letter_type="business"))
|
||||
|
||||
print("\n--- Business Letter HTML Preview (Full Block, no Letterhead) ---")
|
||||
print(get_letter_preview_html(sample_business_content, sample_business_metadata_no_letterhead, letter_type="business"))
|
||||
|
||||
print("\n--- Cover Letter HTML Preview ---")
|
||||
print(get_letter_preview_html(sample_cover_letter_content, sample_cover_letter_metadata, letter_type="cover"))
|
||||
|
||||
print("\n--- Unknown Type HTML Preview ---")
|
||||
print(get_letter_preview_html("Some random content.", {}, letter_type="unknown"))
|
||||
988
lib/ai_writers/ai_letter_writer/utils/letter_templates.py
Normal file
988
lib/ai_writers/ai_letter_writer/utils/letter_templates.py
Normal file
@@ -0,0 +1,988 @@
|
||||
"""
|
||||
Letter Templates Module
|
||||
|
||||
This module provides structured templates and guidance for generating
|
||||
different types and subtypes of letters.
|
||||
Templates are defined as dictionaries containing a 'structure' (list of sections)
|
||||
and 'guidance' (a string).
|
||||
"""
|
||||
|
||||
from typing import Dict, Any, List
|
||||
|
||||
# Define letter templates using a nested dictionary structure for easier management
|
||||
TEMPLATES: Dict[str, Dict[str, Dict[str, Any]]] = {
|
||||
"personal": {
|
||||
"congratulations": {
|
||||
"structure": [
|
||||
"Greeting",
|
||||
"Express congratulations",
|
||||
"Acknowledge the achievement",
|
||||
"Share personal thoughts/memory (optional)",
|
||||
"Look to the future/well wishes",
|
||||
"Closing"
|
||||
],
|
||||
"guidance": "Be warm, sincere, and specific about the achievement. Express genuine happiness for the recipient. Keep the tone personal and friendly."
|
||||
},
|
||||
"thank_you": {
|
||||
"structure": [
|
||||
"Greeting",
|
||||
"Express gratitude clearly",
|
||||
"Specify what you are thankful for",
|
||||
"Explain the impact or how you used it (optional)",
|
||||
"Share a personal thought or memory (optional)",
|
||||
"Offer reciprocation or look to the future",
|
||||
"Closing"
|
||||
],
|
||||
"guidance": "Be specific about what you're thankful for and how it affected you. Express sincere appreciation. Personalize the message."
|
||||
},
|
||||
"sympathy": {
|
||||
"structure": [
|
||||
"Greeting",
|
||||
"Express sympathy for the loss",
|
||||
"Acknowledge the significance of the person/situation",
|
||||
"Share a positive memory or quality (optional)",
|
||||
"Offer specific support (optional)",
|
||||
"Closing with comforting words"
|
||||
],
|
||||
"guidance": "Be gentle, compassionate, and sincere. Avoid clichés. Focus on offering genuine comfort and acknowledging the recipient's feelings."
|
||||
},
|
||||
"apology": {
|
||||
"structure": [
|
||||
"Greeting",
|
||||
"Clearly state your apology",
|
||||
"Acknowledge the specific mistake or action",
|
||||
"Express understanding of the impact on the other person",
|
||||
"Explain (briefly, without making excuses) what happened (optional)",
|
||||
"Offer amends or suggest how to make things right",
|
||||
"Assure it won't happen again",
|
||||
"Closing"
|
||||
],
|
||||
"guidance": "Be sincere, take full responsibility for your actions, and focus on making things right. Avoid making excuses or blaming others."
|
||||
},
|
||||
"invitation": {
|
||||
"structure": [
|
||||
"Greeting",
|
||||
"Clearly state the invitation",
|
||||
"Provide full event details (What, When, Where)",
|
||||
"Explain the significance or purpose (optional)",
|
||||
"Mention who else might be there (optional)",
|
||||
"Request RSVP (date and contact method)",
|
||||
"Express anticipation",
|
||||
"Closing"
|
||||
],
|
||||
"guidance": "Be clear and specific about the details (what, when, where, why). Make it easy for the person to respond."
|
||||
},
|
||||
"friendship": {
|
||||
"structure": [
|
||||
"Greeting",
|
||||
"Express appreciation for the friendship",
|
||||
"Share a recent memory or anecdote",
|
||||
"Acknowledge the value of the relationship",
|
||||
"Check in on them or share updates",
|
||||
"Look to the future (getting together, etc.)",
|
||||
"Closing"
|
||||
],
|
||||
"guidance": "Be warm, personal, and specific about what you value in the friendship. Share updates and show genuine interest."
|
||||
},
|
||||
"love": {
|
||||
"structure": [
|
||||
"Greeting (Terms of endearment)",
|
||||
"Express depth of feelings",
|
||||
"Share a cherished memory or moment",
|
||||
"Describe specific qualities you love and appreciate",
|
||||
"Reaffirm commitment or future hopes",
|
||||
"Closing (Terms of endearment)"
|
||||
],
|
||||
"guidance": "Be sincere, personal, and specific about your feelings. Use sensory details and emotional language appropriate for your relationship."
|
||||
},
|
||||
"encouragement": {
|
||||
"structure": [
|
||||
"Greeting",
|
||||
"Acknowledge the situation or challenge they face",
|
||||
"Express belief in their abilities/strength",
|
||||
"Offer specific words of encouragement or support",
|
||||
"Remind them of past successes (optional)",
|
||||
"Offer practical help (optional)",
|
||||
"Look to the future with hope",
|
||||
"Closing with support"
|
||||
],
|
||||
"guidance": "Be positive, supportive, and specific about the person's strengths and abilities. Offer genuine encouragement and belief in them."
|
||||
},
|
||||
"farewell": {
|
||||
"structure": [
|
||||
"Greeting",
|
||||
"State the purpose (saying goodbye)",
|
||||
"Express feelings about their departure (sadness, happiness for them)",
|
||||
"Share a positive memory or highlight their contribution",
|
||||
"Express good wishes for their future endeavors",
|
||||
"Look to staying in touch (optional)",
|
||||
"Closing"
|
||||
],
|
||||
"guidance": "Be warm, reflective, and forward-looking. Focus on positive memories and express genuine good wishes for their next steps."
|
||||
},
|
||||
# Default personal letter template if subtype is not found
|
||||
"default": {
|
||||
"structure": [
|
||||
"Greeting",
|
||||
"Introduction",
|
||||
"Main content paragraphs",
|
||||
"Closing thoughts",
|
||||
"Signature"
|
||||
],
|
||||
"guidance": "Be personal, authentic, and appropriate for your relationship with the recipient. The tone is typically informal to semi-formal."
|
||||
}
|
||||
},
|
||||
"formal": {
|
||||
"application": {
|
||||
"structure": [
|
||||
"Sender's contact information",
|
||||
"Date",
|
||||
"Recipient's contact information (if known)",
|
||||
"Subject line (Clear and concise)",
|
||||
"Salutation (Formal)",
|
||||
"Introduction (State position applied for and where you saw it)",
|
||||
"Body paragraphs (Highlight relevant skills and experience)",
|
||||
"Closing paragraph (Reiterate interest, mention enclosed resume, call to action)",
|
||||
"Complimentary close (Formal)",
|
||||
"Signature (Typed name)",
|
||||
"Enclosures (Mention if attaching resume/portfolio)"
|
||||
],
|
||||
"guidance": "Be professional, concise, and specific about your qualifications and genuine interest in the position. Tailor it to the specific job description."
|
||||
},
|
||||
"complaint": {
|
||||
"structure": [
|
||||
"Sender's contact information",
|
||||
"Date",
|
||||
"Recipient's contact information",
|
||||
"Subject line (Clearly state it's a complaint)",
|
||||
"Salutation (Formal)",
|
||||
"Introduction (State the purpose: complaint about X service/product)",
|
||||
"Problem description (Provide specific details: date, time, location, product details, names if applicable)",
|
||||
"Impact statement (Explain how the problem affected you)",
|
||||
"Requested resolution (Clearly state what you want: refund, replacement, action)",
|
||||
"Closing paragraph (Reference attached documents, state expectation for response)",
|
||||
"Complimentary close (Formal)",
|
||||
"Signature (Typed name)"
|
||||
],
|
||||
"guidance": "Be clear, factual, and specific about the issue and your desired resolution. Maintain a respectful but firm tone. Include all relevant details."
|
||||
},
|
||||
"request": {
|
||||
"structure": [
|
||||
"Sender's contact information",
|
||||
"Date",
|
||||
"Recipient's contact information",
|
||||
"Subject line (Clearly state the request)",
|
||||
"Salutation (Formal)",
|
||||
"Introduction (State the purpose: making a request)",
|
||||
"Request details (Clearly explain what you are requesting)",
|
||||
"Justification (Explain why the request is necessary or beneficial)",
|
||||
"Provide supporting information (optional)",
|
||||
"Closing paragraph (Express gratitude for consideration, reiterate call to action)",
|
||||
"Complimentary close (Formal)",
|
||||
"Signature (Typed name)"
|
||||
],
|
||||
"guidance": "Be clear, specific, and courteous about your request. Explain why it's important or beneficial to the recipient or organization."
|
||||
},
|
||||
"recommendation": {
|
||||
"structure": [
|
||||
"Sender's contact information",
|
||||
"Date",
|
||||
"Recipient's contact information",
|
||||
"Subject line (Letter of Recommendation for [Name])",
|
||||
"Salutation (Formal)",
|
||||
"Introduction (State your name, title, relationship to the recommendee, and for what purpose the letter is written)",
|
||||
"Body paragraphs (Describe the recommendee's qualifications, skills, and achievements with specific examples)",
|
||||
"Highlight relevant experiences and contributions",
|
||||
"Closing recommendation (Summarize endorsement, strongly recommend the person)",
|
||||
"Complimentary close (Formal)",
|
||||
"Signature (Typed name and title)"
|
||||
],
|
||||
"guidance": "Be specific, positive, and credible. Use concrete examples and anecdotes to support your recommendation. Tailor it to the specific role/opportunity."
|
||||
},
|
||||
"resignation": {
|
||||
"structure": [
|
||||
"Sender's contact information",
|
||||
"Date",
|
||||
"Recipient's contact information (Immediate supervisor/HR)",
|
||||
"Subject line (Letter of Resignation - [Your Name])",
|
||||
"Salutation (Formal)",
|
||||
"Statement of resignation (Clearly state you are resigning)",
|
||||
"Last day of employment (Specify the date)",
|
||||
"Gratitude and reflection (Optional: Express thanks for the opportunity/experience)",
|
||||
"Transition plan/Offer of assistance (Optional: Suggest how to ensure a smooth handover)",
|
||||
"Closing paragraph (Express good wishes for the company's future)",
|
||||
"Complimentary close (Formal)",
|
||||
"Signature (Typed name)"
|
||||
],
|
||||
"guidance": "Be professional, positive (if possible), and clear about your departure and last day. Maintain a good relationship."
|
||||
},
|
||||
"inquiry": {
|
||||
"structure": [
|
||||
"Sender's contact information",
|
||||
"Date",
|
||||
"Recipient's contact information",
|
||||
"Subject line (Clearly state the nature of the inquiry)",
|
||||
"Salutation (Formal)",
|
||||
"Introduction (State your purpose for writing - making an inquiry)",
|
||||
"Inquiry details (Provide necessary context or background)",
|
||||
"Specific questions (List your questions clearly, perhaps numbered)",
|
||||
"Closing paragraph (Express gratitude for assistance, indicate when you need a response)",
|
||||
"Complimentary close (Formal)",
|
||||
"Signature (Typed name)"
|
||||
],
|
||||
"guidance": "Be clear, specific, and courteous about your inquiry. Organize your questions logically for easy answering."
|
||||
},
|
||||
"authorization": {
|
||||
"structure": [
|
||||
"Sender's contact information (The grantor of authority)",
|
||||
"Date",
|
||||
"Recipient's contact information (The person/entity receiving the letter)",
|
||||
"Subject line (Letter of Authorization)",
|
||||
"Salutation (Formal)",
|
||||
"Statement of authorization (Clearly state who is authorized)",
|
||||
"Authorized person's details (Full name, ID if applicable)",
|
||||
"Scope of authority (Precisely define what they are authorized to do)",
|
||||
"Limitations (Specify any restrictions or conditions)",
|
||||
"Duration of authorization (Start and end dates, if applicable)",
|
||||
"Closing paragraph (State responsibility, express confidence)",
|
||||
"Complimentary close (Formal)",
|
||||
"Signature (Typed name and title)"
|
||||
],
|
||||
"guidance": "Be clear, specific, and precise about who is authorized, what they can do, for how long, and under what conditions. This is a legal document."
|
||||
},
|
||||
"appeal": {
|
||||
"structure": [
|
||||
"Sender's contact information",
|
||||
"Date",
|
||||
"Recipient's contact information (Appeals committee/relevant authority)",
|
||||
"Subject line (Letter of Appeal - [Your Name] - [Subject of Appeal])",
|
||||
"Salutation (Formal)",
|
||||
"Introduction (State your name, the decision being appealed, and the date of the decision)",
|
||||
"Grounds for appeal (Clearly state the reasons why you believe the decision is incorrect)",
|
||||
"Provide supporting evidence (Reference attached documents: records, photos, etc.)",
|
||||
"Explain mitigating circumstances (Optional)",
|
||||
"Requested outcome (Clearly state what resolution you seek)",
|
||||
"Closing paragraph (Express hope for reconsideration, gratitude for time)",
|
||||
"Complimentary close (Formal)",
|
||||
"Signature (Typed name)"
|
||||
],
|
||||
"guidance": "Be respectful, factual, and persuasive. Focus on valid grounds for appeal and provide clear, supporting evidence. Maintain a formal tone."
|
||||
},
|
||||
"introduction": {
|
||||
"structure": [
|
||||
"Sender's contact information",
|
||||
"Date",
|
||||
"Recipient's contact information",
|
||||
"Subject line (Introduction - [Your Name])",
|
||||
"Salutation (Formal)",
|
||||
"Introduction (Introduce yourself and the purpose of the letter)",
|
||||
"Background information (Briefly describe your relevant background or expertise)",
|
||||
"Reason for reaching out (Explain why you are introducing yourself to this specific person/entity)",
|
||||
"Potential areas of collaboration or shared interest (Optional)",
|
||||
"Call to action (Suggest a meeting, call, or further communication)",
|
||||
"Closing paragraph (Express enthusiasm for potential connection)",
|
||||
"Complimentary close (Formal)",
|
||||
"Signature (Typed name)"
|
||||
],
|
||||
"guidance": "Be professional, informative, and engaging. Clearly explain who you are, your expertise, and why you're reaching out to them specifically."
|
||||
},
|
||||
# Default formal letter template if subtype is not found
|
||||
"default": {
|
||||
"structure": [
|
||||
"Sender's address",
|
||||
"Date",
|
||||
"Recipient's address",
|
||||
"Subject line",
|
||||
"Salutation",
|
||||
"Introduction",
|
||||
"Body paragraphs",
|
||||
"Closing paragraph",
|
||||
"Complimentary close",
|
||||
"Signature"
|
||||
],
|
||||
"guidance": "Be professional, clear, and concise. Use formal language and structure. The tone is typically formal."
|
||||
}
|
||||
},
|
||||
"business": {
|
||||
"sales": {
|
||||
"structure": [
|
||||
"Letterhead",
|
||||
"Date",
|
||||
"Recipient's address",
|
||||
"Subject line (Benefit-oriented)",
|
||||
"Salutation",
|
||||
"Attention-grabbing opening (Address a pain point or introduce a benefit)",
|
||||
"Problem statement (Briefly describe the challenge the recipient faces)",
|
||||
"Solution presentation (Introduce your product/service as the solution)",
|
||||
"Benefits and features (Explain how your solution helps, focusing on benefits)",
|
||||
"Social proof (Optional: Testimonials, case studies, data)",
|
||||
"Call to action (Clearly state what you want them to do next)",
|
||||
"Closing paragraph (Reiterate benefit, create urgency/incentive)",
|
||||
"Complimentary close (Professional)",
|
||||
"Signature (Typed name and title)",
|
||||
"Enclosures (Optional: Brochure, pricing)"
|
||||
],
|
||||
"guidance": "Be persuasive, customer-focused, and clear about the value proposition. Focus on benefits, not just features. Make the call to action obvious."
|
||||
},
|
||||
"proposal": {
|
||||
"structure": [
|
||||
"Letterhead",
|
||||
"Date",
|
||||
"Recipient's address",
|
||||
"Subject line (Clear and descriptive)",
|
||||
"Salutation",
|
||||
"Introduction (State purpose: submitting a proposal)",
|
||||
"Problem statement/Needs assessment (Demonstrate understanding of client's needs)",
|
||||
"Proposed solution (Describe your solution in detail)",
|
||||
"Implementation plan (Outline steps and timeline)",
|
||||
"Costs and investment (Clearly state pricing and payment terms)",
|
||||
"Benefits and ROI (Explain the value the client will receive)",
|
||||
"Call to action (Suggest next steps: meeting, discussion)",
|
||||
"Closing paragraph (Express enthusiasm, availability for questions)",
|
||||
"Complimentary close (Professional)",
|
||||
"Signature (Typed name and title)",
|
||||
"Enclosures (Proposal document, appendix)"
|
||||
],
|
||||
"guidance": "Be clear, specific, and persuasive about your solution. Focus on the client's needs and the value you provide. Structure it logically."
|
||||
},
|
||||
"order": {
|
||||
"structure": [
|
||||
"Letterhead (Your company)",
|
||||
"Date",
|
||||
"Recipient's address (Supplier)",
|
||||
"Subject line (Purchase Order - [PO Number])",
|
||||
"Salutation",
|
||||
"Introduction (Reference quote/agreement, state purpose: placing an order)",
|
||||
"Order details (Item list with quantities, descriptions, unit prices, total)",
|
||||
"Delivery requirements (Shipping address, requested delivery date, shipping method)",
|
||||
"Payment terms (Reference agreed terms)",
|
||||
"Closing paragraph (Express expectation for timely delivery)",
|
||||
"Complimentary close (Professional)",
|
||||
"Signature (Typed name and title)"
|
||||
],
|
||||
"guidance": "Be clear, specific, and detailed about what you're ordering, quantities, delivery requirements, and payment terms. Include a purchase order number."
|
||||
},
|
||||
"quotation": {
|
||||
"structure": [
|
||||
"Letterhead (Your company)",
|
||||
"Date",
|
||||
"Recipient's address (Customer)",
|
||||
"Subject line (Quotation for [Product/Service])",
|
||||
"Salutation",
|
||||
"Introduction (Reference inquiry, state purpose: providing a quotation)",
|
||||
"Quotation details (List items/services, descriptions, unit prices, quantities, line totals)",
|
||||
"Pricing breakdown (Mention taxes, discounts, fees separately)",
|
||||
"Terms and conditions (Payment terms, delivery terms, warranty)",
|
||||
"Validity period (State how long the quote is valid)",
|
||||
"Next steps (How they can place an order)",
|
||||
"Closing paragraph (Express hope to do business, offer further assistance)",
|
||||
"Complimentary close (Professional)",
|
||||
"Signature (Typed name and title)"
|
||||
],
|
||||
"guidance": "Be clear, specific, and transparent about pricing, terms, and what's included or excluded. Make it easy for the customer to understand and accept."
|
||||
},
|
||||
"acknowledgment": {
|
||||
"structure": [
|
||||
"Letterhead",
|
||||
"Date",
|
||||
"Recipient's address",
|
||||
"Subject line (Acknowledgment of [Received Item/Request])",
|
||||
"Salutation",
|
||||
"Acknowledgment statement (Clearly state what you have received or are acknowledging)",
|
||||
"Details of what's being acknowledged (Reference number, date, brief description)",
|
||||
"Confirm understanding (Optional: Briefly restate the request/issue to show understanding)",
|
||||
"Next steps (Outline what will happen next, e.g., processing order, investigating issue)",
|
||||
"Timeline (Provide an estimated timeframe if possible)",
|
||||
"Closing paragraph (Express gratitude, offer further assistance)",
|
||||
"Complimentary close (Professional)",
|
||||
"Signature (Typed name and title)"
|
||||
],
|
||||
"guidance": "Be prompt, clear, and specific about what you're acknowledging. Set clear expectations for next steps and timelines."
|
||||
},
|
||||
"collection": {
|
||||
"structure": [
|
||||
"Letterhead",
|
||||
"Date",
|
||||
"Recipient's address",
|
||||
"Subject line (Invoice [Invoice Number] - Payment Due)",
|
||||
"Salutation",
|
||||
"Introduction (Reference invoice number and due date)",
|
||||
"Account status (Clearly state the outstanding amount)",
|
||||
"Payment request (Politely request payment)",
|
||||
"Payment options (Remind them how to pay)",
|
||||
"Consequences of non-payment (Optional: Briefly mention late fees or further action, depending on letter stage)",
|
||||
"Call to action (Request payment by a specific date)",
|
||||
"Closing paragraph (Express hope for prompt payment, offer to discuss)",
|
||||
"Complimentary close (Professional)",
|
||||
"Signature (Typed name and title)"
|
||||
],
|
||||
"guidance": "Be firm but professional. Clearly state the amount due, due date, and payment options. The tone may vary depending on how overdue the payment is."
|
||||
},
|
||||
"adjustment": {
|
||||
"structure": [
|
||||
"Letterhead",
|
||||
"Date",
|
||||
"Recipient's address (Customer who made a complaint)",
|
||||
"Subject line (Response to your inquiry - [Reference Number])",
|
||||
"Salutation",
|
||||
"Acknowledgment of complaint (Reference their communication and the issue)",
|
||||
"Investigation findings (Explain the outcome of your investigation)",
|
||||
"Adjustment offered (Clearly state the resolution: refund, replacement, credit, etc.)",
|
||||
"Apology (Optional: Express regret for the inconvenience)",
|
||||
"Preventive measures (Optional: Explain steps taken to prevent recurrence)",
|
||||
"Closing paragraph (Express hope for continued business, offer further assistance)",
|
||||
"Complimentary close (Professional)",
|
||||
"Signature (Typed name and title)"
|
||||
],
|
||||
"guidance": "Be responsive, empathetic, and solution-oriented. Clearly explain the adjustment and any preventive measures taken."
|
||||
},
|
||||
"credit": {
|
||||
"structure": [
|
||||
"Letterhead",
|
||||
"Date",
|
||||
"Recipient's address (Applicant)",
|
||||
"Subject line (Credit Application Status - [Applicant Name])",
|
||||
"Salutation",
|
||||
"Introduction (Reference their credit application and the purpose of the letter)",
|
||||
"Credit decision (Clearly state if credit is approved or denied)",
|
||||
"If approved: Credit terms (Credit limit, payment terms, interest rates)",
|
||||
"If denied: Reason for decision (Provide specific, compliant reasons)",
|
||||
"Requirements (If approved: any further steps or documents needed)",
|
||||
"Closing paragraph (If approved: Express welcome; If denied: Offer alternative options or appeals process)",
|
||||
"Complimentary close (Professional)",
|
||||
"Signature (Typed name and title)"
|
||||
],
|
||||
"guidance": "Be clear, specific, and transparent about the credit decision, terms, limits, or reasons for denial. Ensure compliance with regulations if denying credit."
|
||||
},
|
||||
"follow_up": {
|
||||
"structure": [
|
||||
"Letterhead",
|
||||
"Date",
|
||||
"Recipient's address",
|
||||
"Subject line (Following up on [Previous Communication/Meeting])",
|
||||
"Salutation",
|
||||
"Reference to previous communication (Mention date, topic, or meeting)",
|
||||
"Purpose of follow-up (Clearly state why you are writing again)",
|
||||
"Action items/Next steps (Remind of agreed-upon actions or propose next steps)",
|
||||
"Provide additional information (Optional)",
|
||||
"Call to action (If applicable, e.g., request a response, schedule a meeting)",
|
||||
"Closing paragraph (Reiterate interest, express anticipation)",
|
||||
"Complimentary close (Professional)",
|
||||
"Signature (Typed name and title)"
|
||||
],
|
||||
"guidance": "Be clear, specific, and action-oriented. Reference previous communication and clearly state the purpose of your follow-up and desired outcome."
|
||||
},
|
||||
# Default business letter template if subtype is not found
|
||||
"default": {
|
||||
"structure": [
|
||||
"Letterhead",
|
||||
"Date",
|
||||
"Recipient's address",
|
||||
"Subject line",
|
||||
"Salutation",
|
||||
"Introduction",
|
||||
"Body paragraphs",
|
||||
"Closing paragraph",
|
||||
"Complimentary close",
|
||||
"Signature"
|
||||
],
|
||||
"guidance": "Be professional, clear, and concise. Focus on the business purpose of your letter. The tone is typically formal to semi-formal."
|
||||
}
|
||||
},
|
||||
"cover": {
|
||||
"standard": {
|
||||
"structure": [
|
||||
"Your contact information",
|
||||
"Date",
|
||||
"Hiring Manager contact information (if known)",
|
||||
"Subject line (Job Application - [Your Name] - [Job Title])",
|
||||
"Salutation (Formal)",
|
||||
"Introduction (State the position you are applying for, where you saw the advertisement, and a brief statement of enthusiasm)",
|
||||
"Body paragraph 1 (Highlight skills and experience directly relevant to the job description - often 1-2 key qualifications)",
|
||||
"Body paragraph 2 (Provide a specific example or anecdote demonstrating your abilities)",
|
||||
"Body paragraph 3 (Connect your passion/goals to the company's mission/values - optional but effective)",
|
||||
"Closing paragraph (Reiterate interest, mention attached resume, express availability for interview)",
|
||||
"Complimentary close (Formal)",
|
||||
"Signature (Typed name)"
|
||||
],
|
||||
"guidance": "Be professional, specific about your most relevant qualifications, and clear about your interest in the position. Tailor every cover letter to the specific job and company."
|
||||
},
|
||||
"career_change": {
|
||||
"structure": [
|
||||
"Your contact information",
|
||||
"Date",
|
||||
"Hiring Manager contact information",
|
||||
"Subject line (Job Application - [Your Name] - [Job Title])",
|
||||
"Salutation",
|
||||
"Introduction (State the position and acknowledge your career transition)",
|
||||
"Body paragraph 1 (Highlight transferable skills from previous roles)",
|
||||
"Body paragraph 2 (Explain your motivation for the career change and how your skills apply)",
|
||||
"Body paragraph 3 (Demonstrate understanding of the new industry/role)",
|
||||
"Closing paragraph (Reiterate enthusiasm, mention enclosed resume, call to action)",
|
||||
"Complimentary close",
|
||||
"Signature"
|
||||
],
|
||||
"guidance": "Focus on transferable skills and explain your career transition. Connect your past experience and new skills directly to the requirements of the target role."
|
||||
},
|
||||
"entry_level": {
|
||||
"structure": [
|
||||
"Your contact information",
|
||||
"Date",
|
||||
"Hiring Manager contact information",
|
||||
"Subject line (Job Application - [Your Name] - [Job Title])",
|
||||
"Salutation",
|
||||
"Introduction (State the position and your enthusiasm for the opportunity as a recent graduate/entrant)",
|
||||
"Body paragraph 1 (Highlight relevant education, coursework, GPA if strong)",
|
||||
"Body paragraph 2 (Describe relevant internships, projects, or volunteer experience)",
|
||||
"Body paragraph 3 (Showcase soft skills: teamwork, communication, eagerness to learn)",
|
||||
"Closing paragraph (Reiterate interest, mention attached resume, express availability for interview)",
|
||||
"Complimentary close",
|
||||
"Signature"
|
||||
],
|
||||
"guidance": "Emphasize education, relevant internships/projects, and transferable skills gained through academic or extracurricular activities. Show strong potential and enthusiasm."
|
||||
},
|
||||
"executive": {
|
||||
"structure": [
|
||||
"Your contact information",
|
||||
"Date",
|
||||
"Recipient's contact information (Senior Executive/Board Member)",
|
||||
"Subject line (Executive Application - [Your Name] - [Position])",
|
||||
"Salutation (Formal)",
|
||||
"Introduction (State position applying for, brief summary of executive profile)",
|
||||
"Body paragraph 1 (Highlight strategic leadership experience and key achievements)",
|
||||
"Body paragraph 2 (Discuss relevant industry expertise and market insights)",
|
||||
"Body paragraph 3 (Describe experience in driving growth, managing teams, achieving results)",
|
||||
"Closing paragraph (Reiterate interest, express desire to discuss contribution to the organization)",
|
||||
"Complimentary close (Formal)",
|
||||
"Signature"
|
||||
],
|
||||
"guidance": "Emphasize strategic leadership experience, significant achievements with measurable results, and industry expertise. Use a confident, authoritative, and forward-looking tone."
|
||||
},
|
||||
"creative": {
|
||||
"structure": [
|
||||
"Your contact information",
|
||||
"Date",
|
||||
"Hiring Manager contact information",
|
||||
"Subject line (Application - [Your Name] - [Creative Role])",
|
||||
"Salutation",
|
||||
"Creative introduction (Engaging hook related to the role or your passion)",
|
||||
"Body paragraph 1 (Highlight relevant creative experience and skills)",
|
||||
"Body paragraph 2 (Reference specific portfolio pieces or projects that showcase your style/abilities)",
|
||||
"Body paragraph 3 (Describe your creative process or approach)",
|
||||
"Closing paragraph (Reiterate enthusiasm, mention attached resume/portfolio link, call to action)",
|
||||
"Complimentary close",
|
||||
"Signature"
|
||||
],
|
||||
"guidance": "Use a more engaging and expressive style appropriate for a creative role while maintaining professionalism. Highlight specific creative achievements and link to your portfolio."
|
||||
},
|
||||
"technical": {
|
||||
"structure": [
|
||||
"Your contact information",
|
||||
"Date",
|
||||
"Hiring Manager contact information",
|
||||
"Subject line (Application - [Your Name] - [Technical Role])",
|
||||
"Salutation (Formal)",
|
||||
"Introduction (State position, source, and brief technical interest)",
|
||||
"Body paragraph 1 (Highlight specific technical skills and proficiencies relevant to the job description)",
|
||||
"Body paragraph 2 (Describe relevant technical projects or challenges you've solved)",
|
||||
"Body paragraph 3 (Discuss problem-solving abilities and experience with relevant technologies)",
|
||||
"Closing paragraph (Reiterate interest, mention attached resume, express availability for technical discussion/interview)",
|
||||
"Complimentary close (Formal)",
|
||||
"Signature"
|
||||
],
|
||||
"guidance": "Focus on technical skills, relevant projects, and problem-solving abilities. Use appropriate technical terminology accurately."
|
||||
},
|
||||
"academic": {
|
||||
"structure": [
|
||||
"Your contact information",
|
||||
"Date",
|
||||
"Recipient's contact information (Search Committee Chair)",
|
||||
"Subject line (Application for [Position] - [Your Name])",
|
||||
"Salutation (Formal)",
|
||||
"Introduction (State the position, the department, and express your strong interest)",
|
||||
"Body paragraph 1 (Discuss your research experience, focus on key projects and contributions)",
|
||||
"Body paragraph 2 (Describe your teaching philosophy and relevant teaching experience)",
|
||||
"Body paragraph 3 (Mention publications, presentations, grants, and other scholarly contributions)",
|
||||
"Closing paragraph (Reiterate enthusiasm for joining the faculty, express availability for interview/presentation)",
|
||||
"Complimentary close (Formal)",
|
||||
"Signature (Typed name)"
|
||||
],
|
||||
"guidance": "Focus on research experience, teaching philosophy, publications, and contributions to the field. Use a scholarly and professional tone suitable for academia."
|
||||
},
|
||||
"remote": {
|
||||
"structure": [
|
||||
"Your contact information",
|
||||
"Date",
|
||||
"Hiring Manager contact information",
|
||||
"Subject line (Remote Application - [Your Name] - [Job Title])",
|
||||
"Salutation",
|
||||
"Introduction (State the remote position, source, and enthusiasm for remote work)",
|
||||
"Body paragraph 1 (Highlight experience working remotely or independently)",
|
||||
"Body paragraph 2 (Emphasize self-management, time management, and organizational skills required for remote work)",
|
||||
"Body paragraph 3 (Describe strong written and verbal communication skills, essential for remote collaboration)",
|
||||
"Closing paragraph (Reiterate interest in the remote role, mention attached resume, express availability for video interview)",
|
||||
"Complimentary close",
|
||||
"Signature"
|
||||
],
|
||||
"guidance": "Emphasize self-motivation, excellent communication skills (especially written), time management, and any prior experience working independently or in remote teams."
|
||||
},
|
||||
"referral": {
|
||||
"structure": [
|
||||
"Your contact information",
|
||||
"Date",
|
||||
"Hiring Manager contact information",
|
||||
"Subject line (Referral Application - [Your Name] - [Job Title] - Referred by [Referrer's Name])",
|
||||
"Salutation",
|
||||
"Referral introduction (Immediately state who referred you and for what position)",
|
||||
"Body paragraph 1 (Briefly explain your connection to the referrer and how you learned about the role)",
|
||||
"Body paragraph 2 (Highlight key qualifications relevant to the job description)",
|
||||
"Body paragraph 3 (Express strong interest in the position and the company)",
|
||||
"Closing paragraph (Reiterate enthusiasm, mention attached resume, express availability for interview)",
|
||||
"Complimentary close",
|
||||
"Signature"
|
||||
],
|
||||
"guidance": "Mention the referral prominently and early. Explain your connection to the referrer and how it aligns with your interest in the role. Still, ensure you highlight your own qualifications."
|
||||
},
|
||||
# Default cover letter template if subtype is not found
|
||||
"default": {
|
||||
"structure": [
|
||||
"Contact information",
|
||||
"Date",
|
||||
"Recipient's information",
|
||||
"Subject line",
|
||||
"Salutation",
|
||||
"Introduction",
|
||||
"Body paragraphs",
|
||||
"Closing paragraph",
|
||||
"Complimentary close",
|
||||
"Signature"
|
||||
],
|
||||
"guidance": "Be professional, specific about your qualifications, and clear about your interest in the position. Tailor your letter to the specific job and company."
|
||||
}
|
||||
},
|
||||
"recommendation": {
|
||||
# Recommendation letters are often considered a subtype of Formal,
|
||||
# but can be a top-level type in some systems. Keeping the structure
|
||||
# consistent with the original request, but noting this potential overlap.
|
||||
"standard": {
|
||||
"structure": [
|
||||
"Sender's contact information",
|
||||
"Date",
|
||||
"Recipient's contact information (e.g., Admissions Committee, Hiring Manager)",
|
||||
"Subject line (Letter of Recommendation for [Name])",
|
||||
"Salutation (Formal)",
|
||||
"Introduction (State your name, title, relationship to the recommendee, how long you've known them, and for what opportunity the letter is written)",
|
||||
"Body paragraph 1 (Describe their relevant skills and qualities, providing specific examples)",
|
||||
"Body paragraph 2 (Discuss their achievements or contributions, with context and impact)",
|
||||
"Body paragraph 3 (Optional: Mention character traits, teamwork, or specific anecdotes)",
|
||||
"Overall Endorsement (Summarize your strong recommendation and why they are a good fit)",
|
||||
"Closing paragraph (Offer to provide further information)",
|
||||
"Complimentary close (Formal)",
|
||||
"Signature (Typed name and title)"
|
||||
],
|
||||
"guidance": "Be specific, positive, and credible. Use concrete examples and anecdotes to support your recommendation. Clearly state your relationship with the person and for what opportunity you are recommending them."
|
||||
},
|
||||
# Default recommendation letter template if subtype is not found
|
||||
"default": {
|
||||
"structure": [
|
||||
"Sender's contact information",
|
||||
"Date",
|
||||
"Recipient's contact information",
|
||||
"Subject line (Letter of Recommendation for [Name])",
|
||||
"Salutation",
|
||||
"Introduction",
|
||||
"Body paragraphs describing qualifications and experiences",
|
||||
"Specific examples and anecdotes",
|
||||
"Overall endorsement and recommendation",
|
||||
"Closing and offer for further information",
|
||||
"Complimentary close",
|
||||
"Signature"
|
||||
],
|
||||
"guidance": "Provide a strong, positive, and specific endorsement based on your professional or academic relationship with the individual."
|
||||
}
|
||||
},
|
||||
"complaint": {
|
||||
# Complaint letters are often considered a subtype of Formal or Business,
|
||||
# but can be a top-level type. Keeping the structure consistent.
|
||||
"product": {
|
||||
"structure": [
|
||||
"Your contact information",
|
||||
"Date",
|
||||
"Company contact information",
|
||||
"Subject line (Complaint Regarding [Product Name/Model])",
|
||||
"Salutation (Formal)",
|
||||
"Introduction (State purpose: complaining about a product, include product name, model, date/place of purchase)",
|
||||
"Problem description (Explain the specific defect or issue with the product in detail)",
|
||||
"History of the problem (Mention if you've tried fixing it, contacted support, etc.)",
|
||||
"Desired resolution (Clearly state if you want a refund, replacement, repair)",
|
||||
"Call to action (State what you expect the company to do and by when)",
|
||||
"Closing paragraph (Reference attached documents like receipt, express expectation for resolution)",
|
||||
"Complimentary close (Formal)",
|
||||
"Signature"
|
||||
],
|
||||
"guidance": "Be clear, factual, and specific about the product issue and your desired resolution. Include all relevant details like model number, date of purchase, and copies of receipts. Maintain a firm but professional tone."
|
||||
},
|
||||
"service": {
|
||||
"structure": [
|
||||
"Your contact information",
|
||||
"Date",
|
||||
"Company/Service Provider contact information",
|
||||
"Subject line (Complaint Regarding [Service Type/Issue])",
|
||||
"Salutation (Formal)",
|
||||
"Introduction (State purpose: complaining about a service received, include date/time/location of service)",
|
||||
"Problem description (Explain the specific issue with the service provided in detail)",
|
||||
"Impact of the issue (Explain how this problem affected you)",
|
||||
"Desired resolution (Clearly state what you want: refund, re-performance of service, compensation)",
|
||||
"Call to action (State what you expect the company to do and by when)",
|
||||
"Closing paragraph (Reference any relevant documents, express expectation for resolution)",
|
||||
"Complimentary close (Formal)",
|
||||
"Signature"
|
||||
],
|
||||
"guidance": "Be clear, factual, and specific about the service issue and your desired resolution. Include details like dates, times, and names of service providers if possible. Maintain a firm but professional tone."
|
||||
},
|
||||
"billing": {
|
||||
"structure": [
|
||||
"Your contact information",
|
||||
"Date",
|
||||
"Company contact information",
|
||||
"Subject line (Complaint Regarding Billing Error - Account #[Your Account Number])",
|
||||
"Salutation (Formal)",
|
||||
"Introduction (State purpose: complaining about a billing error, include account number and invoice number)",
|
||||
"Problem description (Explain the specific error on the bill: incorrect charge, double billing, etc.)",
|
||||
"Provide supporting evidence (Reference payments made, attach relevant statements)",
|
||||
"Desired resolution (Clearly state what you want: correction of bill, refund, credit)",
|
||||
"Call to action (State what you expect the company to do and by when)",
|
||||
"Closing paragraph (Reference attached documents, express expectation for resolution)",
|
||||
"Complimentary close (Formal)",
|
||||
"Signature"
|
||||
],
|
||||
"guidance": "Be clear, factual, and specific about the billing error. Provide supporting documentation like invoices or payment records. Clearly state the desired correction."
|
||||
},
|
||||
# Default complaint letter template if subtype is not found
|
||||
"default": {
|
||||
"structure": [
|
||||
"Your contact information",
|
||||
"Date",
|
||||
"Recipient's contact information",
|
||||
"Subject line (Complaint Regarding [Issue Summary])",
|
||||
"Salutation",
|
||||
"Introduction (State the purpose of the letter - to complain)",
|
||||
"Detailed description of the problem",
|
||||
"Explanation of the impact",
|
||||
"Desired resolution",
|
||||
"Call to action",
|
||||
"Closing",
|
||||
"Signature"
|
||||
],
|
||||
"guidance": "Be clear, factual, and specific about the issue and your desired resolution. Maintain a respectful but firm tone and provide relevant details."
|
||||
}
|
||||
},
|
||||
"thank_you": {
|
||||
# Thank You letters are often considered a subtype of Personal or Business,
|
||||
# but can be a top-level type. Keeping the structure consistent.
|
||||
"personal": {
|
||||
"structure": [
|
||||
"Greeting",
|
||||
"Express gratitude clearly and sincerely",
|
||||
"Specify what you are thankful for (gift, favor, support)",
|
||||
"Explain the impact it had on you or how you used it",
|
||||
"Share a personal thought or memory related to it (optional)",
|
||||
"Look to the future or express continued appreciation",
|
||||
"Closing"
|
||||
],
|
||||
"guidance": "Be warm, sincere, and specific about what you are thankful for. Personalize the message and explain the impact of their action or gift."
|
||||
},
|
||||
"professional": {
|
||||
"structure": [
|
||||
"Sender's contact information",
|
||||
"Date",
|
||||
"Recipient's contact information",
|
||||
"Subject line (Thank You - [Your Name])",
|
||||
"Salutation (Formal/Semi-formal)",
|
||||
"Express gratitude clearly (e.g., Thank you for the interview, thank you for your help)",
|
||||
"Specify what you are thankful for (Meeting date/topic, specific assistance)",
|
||||
"Reiterate interest or connection (e.g., Reiterate interest in the job, mention something discussed)",
|
||||
"Express appreciation for their time or effort",
|
||||
"Closing paragraph (Optional: look to future interaction)",
|
||||
"Complimentary close (Formal/Semi-formal)",
|
||||
"Signature"
|
||||
],
|
||||
"guidance": "Be prompt, professional, and specific. Reiterate your interest or key points discussed. Send within 24 hours for interviews."
|
||||
},
|
||||
"after_interview": {
|
||||
"structure": [
|
||||
"Your contact information",
|
||||
"Date",
|
||||
"Interviewer's contact information",
|
||||
"Subject line (Thank You - [Your Name] - [Job Title])",
|
||||
"Salutation (Formal)",
|
||||
"Express sincere thanks for the interview opportunity",
|
||||
"Mention the specific position and date of the interview",
|
||||
"Reiterate your strong interest in the role and the company",
|
||||
"Reference a specific point discussed during the interview to show engagement",
|
||||
"Briefly highlight how your skills/experience align with a need discussed",
|
||||
"Express enthusiasm for next steps",
|
||||
"Complimentary close (Formal)",
|
||||
"Signature"
|
||||
],
|
||||
"guidance": "Send within 24 hours of the interview. Be specific, professional, and reiterate your key strengths and interest. Proofread carefully."
|
||||
},
|
||||
# Default thank you letter template if subtype is not found
|
||||
"default": {
|
||||
"structure": [
|
||||
"Greeting",
|
||||
"Express thanks",
|
||||
"Specify reason for thanks",
|
||||
"Closing"
|
||||
],
|
||||
"guidance": "Be sincere and specific about what you are thankful for."
|
||||
}
|
||||
},
|
||||
"invitation": {
|
||||
# Invitation letters are often considered a subtype of Personal or Formal,
|
||||
# but can be a top-level type. Keeping the structure consistent.
|
||||
"event": { # e.g., party, gathering, wedding
|
||||
"structure": [
|
||||
"Greeting",
|
||||
"State the purpose: extending an invitation",
|
||||
"Event details (Type of event, Host)",
|
||||
"Date and Time",
|
||||
"Location (Full address)",
|
||||
"Purpose/Theme (Optional)",
|
||||
"Special instructions (Dress code, what to bring, etc. - optional)",
|
||||
"RSVP information (Date, Contact method)",
|
||||
"Express anticipation",
|
||||
"Closing"
|
||||
],
|
||||
"guidance": "Be clear about all the event details (What, When, Where). Make it easy for guests to RSVP. Tone can be formal or informal depending on the event."
|
||||
},
|
||||
"interview": {
|
||||
"structure": [
|
||||
"Company Letterhead",
|
||||
"Date",
|
||||
"Candidate's contact information",
|
||||
"Subject line (Interview Invitation - [Job Title] - [Your Name])",
|
||||
"Salutation (Formal)",
|
||||
"State the purpose: inviting them for an interview",
|
||||
"Specify the position applied for",
|
||||
"Propose date(s) and time(s) for the interview",
|
||||
"Provide location details (Address, or link for virtual)",
|
||||
"Mention who they will meet with (Names and titles)",
|
||||
"Explain the interview format/duration (Optional)",
|
||||
"Instructions (What to bring, who to contact with questions)",
|
||||
"Call to action (Request confirmation or scheduling)",
|
||||
"Closing paragraph (Express anticipation)",
|
||||
"Complimentary close (Formal)",
|
||||
"Signature (Interviewer/HR Contact Name and Title)"
|
||||
],
|
||||
"guidance": "Be professional, clear, and provide all necessary details for the candidate. Make the scheduling process straightforward."
|
||||
},
|
||||
"meeting": {
|
||||
"structure": [
|
||||
"Sender's contact information",
|
||||
"Date",
|
||||
"Recipient's contact information",
|
||||
"Subject line (Invitation to Meeting - [Meeting Topic])",
|
||||
"Salutation",
|
||||
"State the purpose: inviting them to a meeting",
|
||||
"Meeting details (Date, Time, Location/Virtual link)",
|
||||
"Purpose/Agenda (Clearly state what the meeting is about)",
|
||||
"Expected duration (Optional)",
|
||||
"Preparation required (Optional: Documents to review)",
|
||||
"RSVP information (Optional)",
|
||||
"Closing paragraph",
|
||||
"Complimentary close",
|
||||
"Signature"
|
||||
],
|
||||
"guidance": "Be clear about the purpose, date, time, and location. Provide an agenda so attendees can prepare. The tone can be formal or informal depending on the context."
|
||||
},
|
||||
# Default invitation letter template if subtype is not found
|
||||
"default": {
|
||||
"structure": [
|
||||
"Greeting",
|
||||
"Invitation statement",
|
||||
"Event/Meeting details (What, When, Where)",
|
||||
"Purpose (Optional)",
|
||||
"RSVP information",
|
||||
"Closing"
|
||||
],
|
||||
"guidance": "Be clear and specific about the details of the event or meeting."
|
||||
}
|
||||
},
|
||||
# Overall default template if letter type is not recognized
|
||||
"default": {
|
||||
"structure": [
|
||||
"Introduction",
|
||||
"Body paragraphs",
|
||||
"Conclusion"
|
||||
],
|
||||
"guidance": "Be clear, concise, and appropriate for your audience and purpose. This is a generic structure."
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
def get_template_by_type(letter_type: str, subtype: str = "default") -> Dict[str, Any]:
|
||||
"""
|
||||
Get a template for a specific letter type and subtype using a dictionary lookup.
|
||||
|
||||
Args:
|
||||
letter_type: Type of letter (e.g., "personal", "formal", "business", "cover").
|
||||
subtype: Subtype of letter (e.g., "congratulations", "application", "sales").
|
||||
Defaults to "default" if no subtype is specified.
|
||||
|
||||
Returns:
|
||||
Template dictionary with 'structure' (List[str]) and 'guidance' (str).
|
||||
Returns the default template if the letter type or subtype is not found.
|
||||
"""
|
||||
# Get templates for the specific letter type, or the overall default templates
|
||||
type_templates = TEMPLATES.get(letter_type, TEMPLATES["default"])
|
||||
|
||||
# Get the template for the specific subtype, or the default for that letter type
|
||||
template = type_templates.get(subtype, type_templates.get("default", TEMPLATES["default"])) # Fallback to overall default
|
||||
|
||||
# Ensure the returned template always has 'structure' and 'guidance' keys
|
||||
# This handles cases where an incomplete template might have been defined (error tolerance)
|
||||
if "structure" not in template or not isinstance(template["structure"], list):
|
||||
template["structure"] = ["Introduction", "Body", "Conclusion"]
|
||||
template["guidance"] = "Generic template: structure or guidance missing."
|
||||
|
||||
if "guidance" not in template or not isinstance(template["guidance"], str):
|
||||
template["guidance"] = "Generic guidance: structure or guidance missing."
|
||||
|
||||
|
||||
return template
|
||||
|
||||
# Example usage (for testing purposes)
|
||||
if __name__ == '__main__':
|
||||
# Test cases
|
||||
print("--- Testing Letter Templates ---")
|
||||
|
||||
personal_congrats = get_template_by_type("personal", "congratulations")
|
||||
print("\nPersonal Congratulations Template:")
|
||||
print(f"Structure: {personal_congrats['structure']}")
|
||||
print(f"Guidance: {personal_congrats['guidance']}")
|
||||
|
||||
formal_complaint = get_template_by_type("formal", "complaint")
|
||||
print("\nFormal Complaint Template:")
|
||||
print(f"Structure: {formal_complaint['structure']}")
|
||||
print(f"Guidance: {formal_complaint['guidance']}")
|
||||
|
||||
business_sales = get_template_by_type("business", "sales")
|
||||
print("\nBusiness Sales Template:")
|
||||
print(f"Structure: {business_sales['structure']}")
|
||||
print(f"Guidance: {business_sales['guidance']}")
|
||||
|
||||
cover_entry_level = get_template_by_type("cover", "entry_level")
|
||||
print("\nCover Entry Level Template:")
|
||||
print(f"Structure: {cover_entry_level['structure']}")
|
||||
print(f"Guidance: {cover_entry_level['guidance']}")
|
||||
|
||||
unknown_type = get_template_by_type("unknown_type", "some_subtype")
|
||||
print("\nUnknown Type Template (Should be Default):")
|
||||
print(f"Structure: {unknown_type['structure']}")
|
||||
print(f"Guidance: {unknown_type['guidance']}")
|
||||
|
||||
personal_unknown_subtype = get_template_by_type("personal", "unknown_subtype")
|
||||
print("\nPersonal Unknown Subtype Template (Should be Personal Default):")
|
||||
print(f"Structure: {personal_unknown_subtype['structure']}")
|
||||
print(f"Guidance: {personal_unknown_subtype['guidance']}")
|
||||
Reference in New Issue
Block a user