Helping my father write letters with OpenAI and Streamlit

Michaël Scherding
5 min readMar 28, 2023

--

Generating a letter can be a time-consuming and daunting task, especially if you are not comfortable with writing and explaining things clearly. That’s where a letter generator can come in handy.

In fact, I came up with this idea to help my father who was struggling with writing letters. I wanted to find a solution that would allow him to be more confident in his writing and provide him with inspiration.

In this tutorial, we will build a web app using Streamlit that generates a letter for you based on the information you provide. We will use OpenAI’s GPT-3 API to generate the body of the letter, and Jinja2 templates to render the letter as HTML.

Getting Started

Before we start, make sure you have the following installed:

  • Python 3.x
  • Streamlit
  • OpenAI’s Python module
  • A OpenAI API key

To install Streamlit and OpenAI’s Python module, run the following commands in your terminal:

pip install streamlit openai

To get an API key for OpenAI, you can sign up here.

Setting Up the Streamlit App

First, we will import the necessary libraries:

from jinja2 import Template
import streamlit as st
import openai

Here, we import Jinja2, Streamlit, and OpenAI’s Python module. Jinja2 is a template engine that allows us to render HTML templates with variables. Streamlit is a library that allows us to build interactive web apps easily. OpenAI’s Python module is a library that allows us to interact with the OpenAI API.

Next, we will set up the OpenAI API key:

# Use secrets
openai.api_key = st.secrets["OPENAI_API_KEY"]

Here, we set the api_key variable to the value of our OpenAI API key, which is stored securely in our Streamlit app's secrets.

We will also set up the Streamlit app:

# Set up the Streamlit app
st.set_page_config(page_title="Letter Generator")

Here, we set the title of our Streamlit app to “Letter Generator”.

Defining the Input Fields

Next, we will define the input fields for the letter:

# Define the input fields for the letter
st.sidebar.title("Letter Generator")
st.sidebar.header("Enter the following information:")

Here, we use the Streamlit sidebar to create a title and a header for our input form.

We will also create two groups of input fields:

# Group 1: Style
with st.sidebar.container():
st.sidebar.header("Style")
tone = st.sidebar.selectbox("Tone: ", ["Friendly", "Cordial", "Direct"])
pronoun = st.sidebar.selectbox("Pronoun: ", ["Formal", "Informal"])

# Group 2: Letter parameters
with st.sidebar.container():
st.sidebar.header("Letter Parameters")
your_name = st.sidebar.text_input("Your Name:")
your_address = st.sidebar.text_area("Your Address:")
tenant_name = st.sidebar.text_input("Tenant Name:")
tenant_address = st.sidebar.text_area("Tenant Address:")
date = st.sidebar.date_input("Date:")
object_text = st.sidebar.text_input("Subject:")

In the first group, we ask the user to choose the tone of the letter and the pronoun to use. In the second group, we ask for information such as the sender’s name and address, the recipient’s name and address, the date, and the subject.

Generating the Letter

Now that we have collected the necessary information, we can generate the letter using OpenAI’s GPT-3 API:

if object_text:
st.sidebar.button("Generate Letter")
st.sidebar.write("")

prompt = f"Write a {tone} letter from the owner {your_name} to the tenant {tenant_name} regarding {object_text} using {pronoun}."
response = openai.Completion.create(
engine="text-davinci-003",
prompt=prompt,
max_tokens=2000,
frequency_penalty=0.5,
n=1,
stop=None,
temperature=0.5,
)
body_text = response.choices[0].text
else:
body_text = ""

Here, we check if the object_text variable is not empty. If it is not, we display a button to generate the letter, and when the button is clicked, we generate the body of the letter using OpenAI's GPT-3 API. We pass in a prompt that includes the information provided by the user, such as the tone, the names, and the subject. We also specify the OpenAI engine to use, the maximum number of tokens to generate, and other parameters that affect the quality and style of the generated text. We save the generated text in the body_text variable.

Rendering the Letter

Finally, we can render the letter using a Jinja2 template:

if body_text:
# Load letter template from HTML file
with open("letter_template.html", "r") as f:
template = Template(f.read())

# Render letter with user input and generated text
letter_html = template.render(
from_name=your_name,
from_address=your_address,
to_name=tenant_name,
to_address=tenant_address,
date=date.strftime("%d %B %Y"),
object_text=object_text,
body_text=body_text,
)

# Display letter as HTML
st.markdown(letter_html, unsafe_allow_html=True)

Here, we check if the body_text variable is not empty. If it is not, we load a Jinja2 template from an HTML file, and render the template with the user input and the generated text. We pass in variables such as the names, the addresses, the date, and the subject to the template, and use the render method to generate the final HTML. We save the HTML in the letter_html variable, and display it using Streamlit's markdown method.

Then you can use .html for your rendering:

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Letter Template</title>
<style>
body {
font-family: Arial, sans-serif;
font-size: 12pt;
line-height: 1.5;
}

.header {
display: flex;
justify-content: space-between;
}

.sender-info {
width: 50%;
}

.recipient-info {
text-align: right;
margin-top: 60px;
width: 50%;
}

.date-info {
text-align: right;
margin-top: 20px;
}

.subject {
margin-top: 20px;
font-weight: bold;
}

.body {
margin-top: 20px;
}
</style>
</head>
<body>
<div class="header">
<div class="sender-info">
<div class="sender-name">de : {{from_name}}</div>
<div class="sender-address">{{from_address}}</div>
</div>
<div class="recipient-info">
<div class="recipient-name">à : {{to_name}}</div>
<div class="recipient-address">{{to_address}}</div>
</div>
</div>
<div class="date-info">{{date}}</div>
<div class="subject">Objet : {{object_text}}</div>
<div class="body">{{body_text}}</div>
</body>
</html>

Result

Next steps

  • add sqlite for saving letters in a table
  • add a pdf generator feature

Conclusion

In this tutorial, we have built a web app using Streamlit that generates a letter for you based on the information you provide. We have used OpenAI’s GPT-3 API to generate the body of the letter, and Jinja2 templates to render the letter as HTML. With a few modifications, you can adapt this code to generate different kinds of letters or documents, such as emails, reports, or resumes.

--

--

No responses yet