Files
ALwrity/ToBeMigrated/ai_writers/ai_letter_writer/main.py
2025-08-06 16:29:49 +05:30

236 lines
9.1 KiB
Python

"""
AI Letter Writer - Main Module
This module provides a comprehensive interface for generating various types of letters
using AI assistance. It supports multiple letter formats, styles, and use cases.
It uses Streamlit for the user interface.
"""
import streamlit as st
# Assuming these modules exist in a package structure
from .letter_types import (
business_letters,
personal_letters,
formal_letters,
cover_letters,
recommendation_letters,
complaint_letters,
thank_you_letters,
invitation_letters
)
# Assuming these utility functions exist
from .utils.letter_formatter import format_letter
from .utils.letter_analyzer import analyze_letter_tone, check_formality
from .utils.letter_templates import get_template_by_type
# Define the letter types and their properties
LETTER_TYPES_CONFIG = [
{
"id": "business",
"name": "Business Letters",
"icon": "💼",
"description": "Professional correspondence for business contexts.",
"color": "#1E88E5", # Blue 600
"module": business_letters
},
{
"id": "personal",
"name": "Personal Letters",
"icon": "💌",
"description": "Heartfelt messages for friends and family.",
"color": "#43A047", # Green 600
"module": personal_letters
},
{
"id": "formal",
"name": "Formal Letters",
"icon": "📜",
"description": "Official correspondence for institutions and authorities.",
"color": "#5E35B1", # Deep Purple 600
"module": formal_letters
},
{
"id": "cover",
"name": "Cover Letters",
"icon": "📋",
"description": "Job application letters to showcase your qualifications.",
"color": "#FB8C00", # Orange 600
"module": cover_letters
},
{
"id": "recommendation",
"name": "Recommendation Letters",
"icon": "👍",
"description": "Endorse colleagues, students, or employees.",
"color": "#00ACC1", # Cyan 600
"module": recommendation_letters
},
{
"id": "complaint",
"name": "Complaint Letters",
"icon": "⚠️",
"description": "Address issues with products, services, or situations.",
"color": "#E53935", # Red 600
"module": complaint_letters
},
{
"id": "thank_you",
"name": "Thank You Letters",
"icon": "🙏",
"description": "Express gratitude for various occasions.",
"color": "#8E24AA", # Purple 600
"module": thank_you_letters
},
{
"id": "invitation",
"name": "Invitation Letters",
"icon": "🎉",
"description": "Invite people to events, interviews, or gatherings.",
"color": "#FFB300", # Amber 600
"module": invitation_letters
}
]
# Map letter type IDs to their modules for easy access
LETTER_MODULES_MAP = {config["id"]: config["module"] for config in LETTER_TYPES_CONFIG}
def initialize_session_state() -> None:
"""Initializes necessary Streamlit session state variables."""
if "letter_type" not in st.session_state:
st.session_state.letter_type = None
if "letter_subtype" not in st.session_state:
st.session_state.letter_subtype = None # Useful if a letter type has subtypes
if "generated_letter" not in st.session_state:
st.session_state.generated_letter = None
if "letter_metadata" not in st.session_state:
# Store information like sender, recipient, date, subject, tone, etc.
st.session_state.letter_metadata = {}
if "letter_input_data" not in st.session_state:
# Store user inputs for letter generation
st.session_state.letter_input_data = {}
def display_letter_type_selection() -> None:
"""Displays the letter type selection interface using a grid of styled containers with buttons."""
st.markdown("## Select Letter Type")
# Create a grid layout for the cards (3 columns)
cols = st.columns(3)
# Display each letter type as a card with a button below it
for i, letter_type_config in enumerate(LETTER_TYPES_CONFIG):
with cols[i % 3]:
# Use markdown to create a styled container for the card appearance
st.markdown(
f"""
<div style="
background-color: {letter_type_config['color']};
padding: 20px;
border-radius: 10px;
margin-bottom: 10px; /* Space between card content and button */
color: white;
min-height: 180px; /* Ensure consistent minimum height */
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
display: flex;
flex-direction: column;
justify-content: space-between; /* Distribute space within the card */
">
<h3 style="margin-top: 0; color: white;">{letter_type_config['icon']} {letter_type_config['name']}</h3>
<p style="color: white;">{letter_type_config['description']}</p>
</div>
""",
unsafe_allow_html=True
)
# Place the Streamlit button below the styled container
# Make the button expand to the width of the column for better alignment with the card
if st.button(
f"Select {letter_type_config['name']}",
key=f"btn_select_{letter_type_config['id']}", # Unique key for each button
use_container_width=True
):
st.session_state.letter_type = letter_type_config['id']
# Clear previous state data when selecting a new type
st.session_state.letter_subtype = None
st.session_state.generated_letter = None
st.session_state.letter_metadata = {}
st.session_state.letter_input_data = {}
st.rerun()
def display_letter_interface(letter_type_id: str) -> None:
"""
Displays the interface for the selected letter type by calling the
appropriate module's write function.
Args:
letter_type_id: The ID string of the selected letter type.
"""
module = LETTER_MODULES_MAP.get(letter_type_id)
if module:
try:
# Call the main function (e.g., write_letter or main) from the selected module
# Assuming the module has a function that renders its UI and handles generation
module.write_letter() # Assuming the function is named 'write_letter'
except AttributeError:
st.error(f"Module for '{letter_type_id}' does not have a 'write_letter' function.")
except Exception as e:
st.error(f"An error occurred while loading the interface for '{letter_type_id}': {e}")
else:
st.error(f"Letter type module '{letter_type_id}' not found in map.")
def write_letter() -> None:
"""Main function for the AI Letter Writer interface."""
# Page title and description
st.title("✉️ AI Letter Writer")
st.markdown("""
Create professional, personalized letters for any occasion. Select a letter type below to get started.
Our AI will help you craft the perfect letter with the right tone, structure, and content.
""")
# Initialize session state on first run
initialize_session_state()
# Back button logic - only show if a letter type is selected
if st.session_state.letter_type is not None:
if st.button("← Back to Letter Types"):
# Reset session state to return to selection
st.session_state.letter_type = None
st.session_state.letter_subtype = None
st.session_state.generated_letter = None
st.session_state.letter_metadata = {}
st.session_state.letter_input_data = {}
st.rerun() # Rerun to show the selection page
# Main navigation logic
if st.session_state.letter_type is None:
# Display letter type selection if no type is selected
display_letter_type_selection()
else:
# Display the interface for the selected letter type
display_letter_interface(st.session_state.letter_type)
# --- Placeholder for displaying generated letter and actions ---
# This part would typically be handled within the specific letter type modules
# after the letter is generated. However, if a common display is needed
# after returning from the module function, it would go here, but this
# requires the module function to somehow signal completion or store
# the generated letter in session state. The current structure expects
# the module's write_letter() to handle its entire lifecycle.
# Example of potentially displaying a generated letter after returning
# (This assumes the module updates st.session_state.generated_letter)
# if st.session_state.generated_letter:
# st.subheader("Generated Letter Preview")
# st.text_area("Your Letter", st.session_state.generated_letter, height=400)
# # Add options like copy, download, analyze, edit, etc.
if __name__ == "__main__":
# Run the main letter writing function when the script is executed
write_letter()