Spaces:
Sleeping
Sleeping
sab
commited on
Commit
·
9b93e00
1
Parent(s):
19c351f
first commit
Browse files- .gitignore +1 -0
- app.py +108 -0
- requirements.txt +4 -0
- utils/__init__.py +0 -0
- utils/mail_generator.py +111 -0
.gitignore
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
.env
|
app.py
ADDED
|
@@ -0,0 +1,108 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
import openai
|
| 3 |
+
import streamlit as st
|
| 4 |
+
from utils.mail_generator import AzureOpenAIEmailGenerator
|
| 5 |
+
|
| 6 |
+
|
| 7 |
+
# Configurazione e costanti
|
| 8 |
+
class Config:
|
| 9 |
+
PAGE_TITLE = "Draftlytics 📧"
|
| 10 |
+
PAGE_ICON = "📬"
|
| 11 |
+
HEADER_COLOR = "#9d03fc"
|
| 12 |
+
ENGINE = "gpt-4"
|
| 13 |
+
CUSTOM_CSS = f"""
|
| 14 |
+
<style>
|
| 15 |
+
.css-1egvi7u {{ margin-top: -4rem; }} /* Move app further up and remove top padding */
|
| 16 |
+
.css-znku1x a {{ color: {HEADER_COLOR}; }} /* Change hyperlink href link color */
|
| 17 |
+
.css-qrbaxs {{ min-height: 0.0rem; }} /* Change height of text input fields headers */
|
| 18 |
+
.stSpinner > div > div {{ border-top-color: {HEADER_COLOR}; }} /* Change spinner color to primary color */
|
| 19 |
+
.css-15tx938 {{ min-height: 0.0rem; }} /* Change min height of text input box */
|
| 20 |
+
header {{ visibility: hidden; }} /* Hide top header line */
|
| 21 |
+
#MainMenu {{ visibility: hidden; }} /* Hide "made with streamlit" footer menu area */
|
| 22 |
+
footer {{ visibility: hidden; }} /* Hide footer */
|
| 23 |
+
</style>
|
| 24 |
+
"""
|
| 25 |
+
|
| 26 |
+
|
| 27 |
+
# Classe principale dell'applicazione
|
| 28 |
+
class DraftlyticsApp:
|
| 29 |
+
def __init__(self):
|
| 30 |
+
self.email_generator = AzureOpenAIEmailGenerator(Config.ENGINE)
|
| 31 |
+
self.email_text = ""
|
| 32 |
+
|
| 33 |
+
def set_page_config(self):
|
| 34 |
+
st.set_page_config(page_title=Config.PAGE_TITLE, page_icon=Config.PAGE_ICON)
|
| 35 |
+
|
| 36 |
+
def apply_custom_css(self):
|
| 37 |
+
st.markdown(Config.CUSTOM_CSS, unsafe_allow_html=True)
|
| 38 |
+
|
| 39 |
+
def display_header(self):
|
| 40 |
+
#st.image('images/rephraise_logo.png', width=100)
|
| 41 |
+
st.markdown(f"# Welcome to {Config.PAGE_TITLE} 📧")
|
| 42 |
+
st.write("### Your Expert AI Email Assistant 🤖")
|
| 43 |
+
|
| 44 |
+
def get_user_input(self):
|
| 45 |
+
st.subheader("📌 What is the main subject of your email?")
|
| 46 |
+
st.write("Note: The generated email will be in English.")
|
| 47 |
+
with st.expander("✉️ Email Input", expanded=True):
|
| 48 |
+
input_c1 = st.text_input('Provide the main topic of your email', '')
|
| 49 |
+
input_c2 = st.text_input('Provide the secondary topic of your email (optional)', '')
|
| 50 |
+
col1, col2, col3, space, col4 = st.columns([5, 5, 5, 0.5, 5])
|
| 51 |
+
|
| 52 |
+
with col1:
|
| 53 |
+
input_sender = st.text_input('Sender Name', '')
|
| 54 |
+
with col2:
|
| 55 |
+
input_recipient = st.text_input('Recipient Name', '')
|
| 56 |
+
with col3:
|
| 57 |
+
input_style = st.selectbox('Writing Style', ('formal', 'motivated', 'concerned', 'disappointed'),
|
| 58 |
+
index=0)
|
| 59 |
+
with col4:
|
| 60 |
+
st.write("\n") # add spacing
|
| 61 |
+
st.write("\n") # add spacing
|
| 62 |
+
if st.button('Generate Email 🚀'):
|
| 63 |
+
with st.spinner('Generating your email... ⏳'):
|
| 64 |
+
self.validate_and_generate_email(input_c1, input_c2, input_sender, input_recipient, input_style)
|
| 65 |
+
|
| 66 |
+
def validate_and_generate_email(self, input_c1, input_c2, input_sender, input_recipient, input_style):
|
| 67 |
+
if not input_c1.strip():
|
| 68 |
+
st.error('⚠️ The main topic is required!')
|
| 69 |
+
return
|
| 70 |
+
if not input_sender.strip():
|
| 71 |
+
st.error('⚠️ The sender name is required!')
|
| 72 |
+
return
|
| 73 |
+
|
| 74 |
+
if not input_recipient.strip():
|
| 75 |
+
st.error('⚠️ The recipient name is required!')
|
| 76 |
+
return
|
| 77 |
+
|
| 78 |
+
input_contents = [input_c1.strip()]
|
| 79 |
+
if input_c2.strip():
|
| 80 |
+
input_contents.append(input_c2.strip())
|
| 81 |
+
|
| 82 |
+
self.email_text = self.email_generator.generate_mail_format(
|
| 83 |
+
input_sender.strip(), input_recipient.strip(), input_style, input_contents
|
| 84 |
+
)
|
| 85 |
+
self.display_email()
|
| 86 |
+
|
| 87 |
+
@st.dialog("📧 RESULT:")
|
| 88 |
+
def display_email(self):
|
| 89 |
+
if self.email_text:
|
| 90 |
+
st.write('\n') # add spacing
|
| 91 |
+
st.markdown(self.email_text)
|
| 92 |
+
|
| 93 |
+
def run(self):
|
| 94 |
+
self.set_page_config()
|
| 95 |
+
self.apply_custom_css()
|
| 96 |
+
self.display_header()
|
| 97 |
+
self.get_user_input()
|
| 98 |
+
|
| 99 |
+
# Funzione principale per eseguire l'applicazione
|
| 100 |
+
|
| 101 |
+
|
| 102 |
+
def main():
|
| 103 |
+
app = DraftlyticsApp()
|
| 104 |
+
app.run()
|
| 105 |
+
|
| 106 |
+
|
| 107 |
+
if __name__ == '__main__':
|
| 108 |
+
main()
|
requirements.txt
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
streamlit==1.39.0
|
| 2 |
+
openai==0.27.4
|
| 3 |
+
python-dotenv
|
| 4 |
+
langchain
|
utils/__init__.py
ADDED
|
File without changes
|
utils/mail_generator.py
ADDED
|
@@ -0,0 +1,111 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
from abc import ABC, abstractmethod
|
| 3 |
+
from dotenv import load_dotenv, find_dotenv
|
| 4 |
+
import openai
|
| 5 |
+
from typing import List
|
| 6 |
+
|
| 7 |
+
|
| 8 |
+
class AIEmailGenerator(ABC):
|
| 9 |
+
"""Abstract base class for generating emails using AI."""
|
| 10 |
+
|
| 11 |
+
@abstractmethod
|
| 12 |
+
def _configure_api(self):
|
| 13 |
+
"""Configure the API settings."""
|
| 14 |
+
pass
|
| 15 |
+
|
| 16 |
+
@abstractmethod
|
| 17 |
+
def generate_mail_contents(self, email_contents: List[str]) -> List[str]:
|
| 18 |
+
"""Generate more formal and elaborate content for each email topic."""
|
| 19 |
+
pass
|
| 20 |
+
|
| 21 |
+
@abstractmethod
|
| 22 |
+
def generate_mail_format(self, sender: str, recipient: str, style: str, email_contents: List[str]) -> str:
|
| 23 |
+
"""Generate a formatted email with updated content."""
|
| 24 |
+
pass
|
| 25 |
+
|
| 26 |
+
|
| 27 |
+
class AzureOpenAIEmailGenerator(AIEmailGenerator):
|
| 28 |
+
"""Concrete class for generating emails using OpenAI on Azure."""
|
| 29 |
+
|
| 30 |
+
def __init__(self, engine: str):
|
| 31 |
+
"""Initialize the AzureOpenAIEmailGenerator class by loading environment variables and configuring OpenAI."""
|
| 32 |
+
self.engine = engine
|
| 33 |
+
self._load_environment()
|
| 34 |
+
self._configure_api()
|
| 35 |
+
|
| 36 |
+
def _load_environment(self):
|
| 37 |
+
"""Load environment variables from .env file."""
|
| 38 |
+
load_dotenv(find_dotenv())
|
| 39 |
+
|
| 40 |
+
def _configure_api(self):
|
| 41 |
+
"""Configure OpenAI API settings."""
|
| 42 |
+
openai.api_type = "azure"
|
| 43 |
+
openai.api_base = os.getenv('OPENAI_API_BASE')
|
| 44 |
+
openai.api_version = "2023-03-15-preview"
|
| 45 |
+
openai.api_key = os.getenv("OPENAI_API_KEY")
|
| 46 |
+
|
| 47 |
+
def generate_mail_contents(self, email_contents: List[str]) -> List[str]:
|
| 48 |
+
"""Generates more formal and elaborate content for each email topic."""
|
| 49 |
+
for i, input_text in enumerate(email_contents):
|
| 50 |
+
prompt = (
|
| 51 |
+
f"Rewrite the text to be elaborate and polite.\n"
|
| 52 |
+
f"Abbreviations need to be replaced.\n"
|
| 53 |
+
f"Text: {input_text}\n"
|
| 54 |
+
f"Rewritten text:"
|
| 55 |
+
)
|
| 56 |
+
response = openai.ChatCompletion.create(
|
| 57 |
+
engine=self.engine,
|
| 58 |
+
messages=[
|
| 59 |
+
{"role": "system", "content": "You are an AI assistant that helps people find information."},
|
| 60 |
+
{"role": "user", "content": prompt}
|
| 61 |
+
],
|
| 62 |
+
temperature=0,
|
| 63 |
+
max_tokens=len(input_text) * 3,
|
| 64 |
+
top_p=0.95,
|
| 65 |
+
frequency_penalty=0,
|
| 66 |
+
presence_penalty=0
|
| 67 |
+
)
|
| 68 |
+
email_contents[i] = response['choices'][0]['message']['content']
|
| 69 |
+
return email_contents
|
| 70 |
+
|
| 71 |
+
def generate_mail_format(self, sender: str, recipient: str, style: str, email_contents: List[str]) -> str:
|
| 72 |
+
"""Generates a formatted email with updated content."""
|
| 73 |
+
email_contents = self.generate_mail_contents(email_contents)
|
| 74 |
+
contents_str = ""
|
| 75 |
+
contents_length = 0
|
| 76 |
+
|
| 77 |
+
for i, content in enumerate(email_contents):
|
| 78 |
+
contents_str += f"\nContent{i + 1}: {content}"
|
| 79 |
+
contents_length += len(content)
|
| 80 |
+
|
| 81 |
+
prompt = (
|
| 82 |
+
f"Write a professional email that sounds {style} and includes Content1 and Content2 in that order.\n\n"
|
| 83 |
+
f"Sender: {sender}\n"
|
| 84 |
+
f"Recipient: {recipient}{contents_str}\n\n"
|
| 85 |
+
f"Email Text:"
|
| 86 |
+
)
|
| 87 |
+
response = openai.ChatCompletion.create(
|
| 88 |
+
engine=self.engine,
|
| 89 |
+
messages=[
|
| 90 |
+
{"role": "system", "content": "You are an AI assistant that helps people find information."},
|
| 91 |
+
{"role": "user", "content": prompt}
|
| 92 |
+
],
|
| 93 |
+
temperature=0,
|
| 94 |
+
max_tokens=contents_length * 2,
|
| 95 |
+
top_p=0.95,
|
| 96 |
+
frequency_penalty=0,
|
| 97 |
+
presence_penalty=0
|
| 98 |
+
)
|
| 99 |
+
return response['choices'][0]['message']['content']
|
| 100 |
+
|
| 101 |
+
# Esempio di utilizzo:
|
| 102 |
+
|
| 103 |
+
if __name__ == "__main__":
|
| 104 |
+
engine = "gpt-4" # Specificare l'engine desiderato
|
| 105 |
+
email_generator = AzureOpenAIEmailGenerator(engine)
|
| 106 |
+
sender = "example_sender@example.com"
|
| 107 |
+
recipient = "example_recipient@example.com"
|
| 108 |
+
style = "formal"
|
| 109 |
+
email_contents = ["This is the first content.", "This is the second content."]
|
| 110 |
+
formatted_email = email_generator.generate_mail_format(sender, recipient, style, email_contents)
|
| 111 |
+
print(formatted_email)
|