ttvemaildrafter / app.py
Alex Stern
Update app.py
d4fb664
from openai import OpenAI
import gradio as gr
from math import floor, log10
import dotenv
dotenv.load_dotenv()
import os
# Initialize OpenAI API
client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"))
def generate_together_tv_email_response(email_content, bullet_points, tone, length, model_choice):
"""
Generates an email response based on the provided content, bullet points, tone, and length.
Chooses between different AI models for response generation.
Parameters:
- email_content: The content of the email to respond to
- bullet_points: Key points to be included in the response
- tone: The desired tone of the response (optional)
- length: Desired length of the email response
- model_choice: AI model to be used for generation (GPT-3.5 or GPT-4)
"""
# Determine the length of the response based on input parameters
email_length = get_email_length(email_content, length)
tone_statement = f"\n\nTone: {tone}" if tone else "\n\nTone: Warm and Kind"
model_choice = model_choice if model_choice else "gpt-3.5-turbo"
# Construct the prompt for the AI model
prompt = (
f"Email context: {email_content}\n\n"
f"Bullet Points: {bullet_points}{tone_statement}\n\n"
f"Response length: {email_length} words\n\n"
"Draft an email response."
)
# Use OpenAI API to generate the email response
try:
response = client.chat.completions.create(
model=model_choice,
messages=[
{
"role": "system",
"content": (
"This task involves generating a response to an email. "
"You will receive the original email, along with specific bullet points that summarize the content the user wishes to address in their response. "
"Additionally, the desired tone for the response will be specified. "
"Your task is to draft an email response that addresses the bullet points, "
"aligns with the tone specified, and reflects the ethos and values of TogetherTV, a TV channel committed to social change and community engagement. "
"Grammar MUST BE in UK English. "
"Be polite and informal unless told otherwise. "
"End the response with a polite closing and a signature from the TogetherTV team."
)
},
{
"role": "user",
"content": prompt
}
],
temperature=0.7,
max_tokens=500,
top_p=1
)
complete_response = response.choices[0].message.content
# Calculate the cost of token usage
cost = calculate_token_usage_price(response, model_choice)
# Return the generated response and the cost
return complete_response, cost
except Exception as e:
print(f"An error occurred: {e}")
return str(e)
def sig_figs(x: float, precision: int):
"""
Rounds a number to a specified number of significant figures.
Parameters:
- x (float): The number to be rounded.
- precision (int): The number of significant figures to round to.
Returns:
- A float rounded to the specified number of significant figures.
"""
x = float(x)
precision = int(precision)
return round(x, -int(floor(log10(abs(x)))) + (precision - 1))
def calculate_token_usage_price(response, model_choice):
"""
Calculates the cost of token usage for a given response and model.
Parameters:
- response: The response object from the OpenAI API.
- model_choice (str): The model used for the response (e.g., 'gpt-3.5-turbo').
Returns:
- The cost of token usage rounded to two significant figures.
"""
tokens_input = response.usage.prompt_tokens
tokens_output = response.usage.completion_tokens
# Define the rate per token based on the model choice
if model_choice == "gpt-3.5-turbo":
rate_input = 0.0010 / 1000
rate_output = 0.0020 / 1000
else: # Assuming gpt-4
rate_input = 0.03 / 1000
rate_output = 0.06 / 1000
# Calculate total cost
cost = (tokens_input * rate_input) + (tokens_output * rate_output)
return sig_figs(cost, 2)
def word_count(word):
"""
Counts the number of words in a given string.
Parameters:
- word (str): The string to count words in.
Returns:
- The number of words in the string.
"""
countOfWords = len(str(word).split())
return countOfWords
def get_email_length(email_content, length):
"""
Determines the email length based on the content and user's choice.
Parameters:
- email_content (str): The content of the email.
- length (str): The user's choice for the response length.
Returns:
- An integer representing the number of words for the email response.
"""
# Mapping of length choices to their respective values
email_length_options = {
"Brief": 50,
"Matching Client's Email Length": round(word_count(email_content)),
"Detailed": 150
}
# Return the length based on user choice, default to 50 if not specified
return email_length_options.get(length, 50)
def gradio_interface():
# Define the Gradio interface for the email response generator
email_example = (
"EXAMPLE:\n"
"Hello,\n\n"
"I recently watched your documentary 'A perfect 14' and found it extremely "
"eye-opening regarding what plus-models have to go through. I appreciate TogetherTV's effort to shed light "
"on such critical topics. Do you have any reccomendations for other documentaries I could watch?\n\n"
"Best regards,\n"
"Jordan Ellis"
)
email_response_bullet_points= (
"EXAMPLE:\n"
"Thanks!\n"
"We agree with you.\n"
"'Gamechangers: Vigilante' is a good one to watch"
)
interface = gr.Interface(
fn=generate_together_tv_email_response,
inputs=[
gr.components.Textbox(placeholder=email_example, lines=8, label="Email content"),
gr.components.Textbox(placeholder=email_response_bullet_points, lines=8, label="Bullet Points"),
gr.components.Textbox(placeholder="E.g., polite, enthusiastic, warm", lines=1, label="Tone"),
gr.Dropdown(["Brief", "Matching Client's Email Length", "Detailed"], label="Email Response Length"),
gr.Dropdown(["gpt-3.5-turbo", "gpt-4"], label="Choose Model")
],
outputs=[
gr.components.Textbox(lines=8, label="Email Response"),
gr.components.Textbox(label="Cost Estimate ($)")
],
title="TTV Email Draft Generator",
description="Craft AI-powered email responses effortlessly. Enter the email content, pinpoint key bullet points, choose the tone, and decide the response length. Opt for GPT-3.5 for solid performance or GPT-4 for enhanced quality."
)
# Launch the Gradio interface
interface.launch(share=True)
if __name__ == "__main__":
gradio_interface()