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 = "[email protected]"
|
107 |
+
recipient = "[email protected]"
|
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)
|