0Learn commited on
Commit
971b0ff
·
verified ·
1 Parent(s): e4354e3

Upload 9 files

Browse files
app (3).py ADDED
@@ -0,0 +1,62 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # app.py
2
+ # Filepath: ai-email-assistant/app.py
3
+ # Main application entry point
4
+
5
+ import json
6
+ import gradio as gr
7
+ from chat import create_chat_interface
8
+ from profile_management import create_profile_management_interface, get_profile_summaries
9
+ from email_actions import create_email_actions_interface, get_template_summaries
10
+ from groq_client import set_api_key
11
+ from google_sheets_utils import connect_to_sheets
12
+
13
+ def load_config():
14
+ try:
15
+ with open('config.json', 'r') as f:
16
+ return json.load(f)
17
+ except FileNotFoundError:
18
+ return {}
19
+
20
+ def main():
21
+ config = load_config()
22
+ api_key = config.get('groq_api_key')
23
+ if api_key:
24
+ set_api_key(api_key)
25
+
26
+ sender_sheet, receiver_sheet, template_sheet = connect_to_sheets()
27
+
28
+ with gr.Blocks() as app:
29
+ gr.Markdown("# AI Email Assistant")
30
+
31
+ # State variables
32
+ current_sender = gr.State(None)
33
+ current_receiver = gr.State(None)
34
+ current_template = gr.State(None)
35
+
36
+ with gr.Tabs():
37
+ with gr.Tab("Profile Management"):
38
+ with gr.Tabs():
39
+ with gr.Tab("Sender Profiles"):
40
+ sender_components = create_profile_management_interface(sender_sheet, "Sender", current_sender)
41
+ with gr.Tab("Receiver Profiles"):
42
+ receiver_components = create_profile_management_interface(receiver_sheet, "Receiver", current_receiver)
43
+
44
+ with gr.Tab("Email Actions"):
45
+ email_actions_components = create_email_actions_interface(template_sheet, current_template)
46
+
47
+ with gr.Tab("Chat"):
48
+ # Get summaries for context
49
+ sender_summaries = get_profile_summaries(sender_sheet)
50
+ receiver_summaries = get_profile_summaries(receiver_sheet)
51
+ template_summaries = get_template_summaries(template_sheet)
52
+
53
+ chat_interface = create_chat_interface(
54
+ sender_summaries, receiver_summaries, template_summaries,
55
+ current_sender, current_receiver, current_template,
56
+ sender_components, receiver_components, email_actions_components
57
+ )
58
+
59
+ app.launch()
60
+
61
+ if __name__ == "__main__":
62
+ main()
chat.py ADDED
@@ -0,0 +1,95 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # chat.py
2
+ # Filepath: ai-email-assistant/chat.py
3
+ # Implements the chat interface and message handling
4
+
5
+ import gradio as gr
6
+ from groq_client import get_ai_response
7
+ from web_search import search_web
8
+ from profile_management import get_profiles, create_profile, update_profile, delete_profile
9
+ from email_actions import get_templates, create_template, update_template, delete_template
10
+
11
+ def load_system_prompt(filename):
12
+ try:
13
+ with open(filename, 'r') as file:
14
+ return file.read().strip()
15
+ except FileNotFoundError:
16
+ return "System prompt file not found."
17
+
18
+ def create_chat_interface(sender_summaries, receiver_summaries, template_summaries,
19
+ current_sender, current_receiver, current_template,
20
+ sender_components, receiver_components, email_actions_components):
21
+ main_system_prompt = load_system_prompt('system_prompt_main.txt')
22
+ function_call_prompt = load_system_prompt('system_prompt_function_call.txt')
23
+
24
+ chatbot = gr.Chatbot()
25
+ msg = gr.Textbox()
26
+ clear = gr.Button("Clear")
27
+
28
+ def get_context():
29
+ context = "Current context:\n"
30
+
31
+ if current_sender.value:
32
+ context += f"Current Sender: {current_sender.value}\n"
33
+ if current_receiver.value:
34
+ context += f"Current Receiver: {current_receiver.value}\n"
35
+ if current_template.value:
36
+ context += f"Current Template: {current_template.value}\n"
37
+
38
+ context += f"Available Sender Profiles: {', '.join(sender_summaries)}\n"
39
+ context += f"Available Receiver Profiles: {', '.join(receiver_summaries)}\n"
40
+ context += f"Available Templates: {', '.join(template_summaries)}\n"
41
+
42
+ return context
43
+
44
+ def execute_function(function_call):
45
+ # Implementation of function execution based on the function call
46
+ # This should handle all the functions mentioned in the system prompt
47
+ function_name = function_call.split('(')[0].strip()
48
+ args = [arg.strip().strip("'\"") for arg in function_call.split('(')[1].split(')')[0].split(',')]
49
+
50
+ if function_name == 'load_sender_profile':
51
+ current_sender.value = args[0]
52
+ return f"Loaded sender profile: {args[0]}"
53
+ elif function_name == 'load_receiver_profile':
54
+ current_receiver.value = args[0]
55
+ return f"Loaded receiver profile: {args[0]}"
56
+ elif function_name == 'load_template':
57
+ current_template.value = args[0]
58
+ return f"Loaded template: {args[0]}"
59
+ # Add more function implementations as needed
60
+
61
+ return "Function not implemented"
62
+
63
+ def respond(message, chat_history):
64
+ context = get_context()
65
+
66
+ main_ai_response = get_ai_response(message, main_system_prompt, context + "\n".join([f"{m[0]}: {m[1]}" for m in chat_history]))
67
+
68
+ if "Action required:" in main_ai_response:
69
+ action_context = main_ai_response.split("Action required:")[1].strip()
70
+ function_call_response = get_ai_response(action_context, function_call_prompt)
71
+
72
+ if function_call_response.startswith('[SEARCH:'):
73
+ search_query = function_call_response[8:-1].strip()
74
+ result = "\n".join(search_web(search_query))
75
+ elif function_call_response.startswith('[FUNCTION:'):
76
+ function_call = function_call_response[10:-1].strip()
77
+ result = execute_function(function_call)
78
+ else:
79
+ result = "Invalid backend response"
80
+
81
+ final_response = get_ai_response(
82
+ f"Previous context: {action_context}\n\nAction result: {result}\n\nPlease continue the conversation with the user based on this result.",
83
+ main_system_prompt,
84
+ "\n".join([f"{m[0]}: {m[1]}" for m in chat_history])
85
+ )
86
+ else:
87
+ final_response = main_ai_response
88
+
89
+ chat_history.append((message, final_response))
90
+ return "", chat_history
91
+
92
+ msg.submit(respond, [msg, chatbot], [msg, chatbot])
93
+ clear.click(lambda: None, None, chatbot, queue=False)
94
+
95
+ return chatbot, msg, clear
email_actions.py ADDED
@@ -0,0 +1,98 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # email_actions.py
2
+ # Filepath: ai-email-assistant/email_actions.py
3
+ # Manages email-related actions (drafting, templating)
4
+
5
+ import gradio as gr
6
+ from google_sheets_utils import get_templates, save_template, delete_template_from_sheet
7
+
8
+ def get_template_summaries(sheet):
9
+ templates = get_templates(sheet)
10
+ return [template[2] for template in templates] # Assuming the name is in the third column
11
+
12
+ def create_email_actions_interface(template_sheet, current_template):
13
+ with gr.Group():
14
+ gr.Markdown("## Email Actions")
15
+
16
+ name = gr.Textbox(label="Template Name")
17
+ subject = gr.Textbox(label="Subject")
18
+ content = gr.Textbox(label="Content", lines=10)
19
+ sender_profile = gr.Dropdown(label="Sender Profile")
20
+ receiver_profile = gr.Dropdown(label="Receiver Profile")
21
+
22
+ save_draft_btn = gr.Button("Save as Draft")
23
+ save_template_btn = gr.Button("Save as Template")
24
+
25
+ templates_list = gr.Dataframe(
26
+ headers=["Type", "ID", "Name", "Subject", "Content", "Sender Profile", "Receiver Profile"],
27
+ label="Existing Templates",
28
+ value=get_templates(template_sheet),
29
+ interactive=False
30
+ )
31
+
32
+ load_template_btn = gr.Button("Load Selected Template")
33
+ delete_template_btn = gr.Button("Delete Selected Template")
34
+
35
+ def save_template_action():
36
+ template_data = {
37
+ "name": name.value,
38
+ "subject": subject.value,
39
+ "content": content.value,
40
+ "sender_profile": sender_profile.value,
41
+ "receiver_profile": receiver_profile.value
42
+ }
43
+ save_template(template_sheet, template_data)
44
+ return get_templates(template_sheet)
45
+
46
+ def load_template(evt: gr.SelectData):
47
+ if evt.value:
48
+ selected_template = templates_list.value[evt.index[0]]
49
+ current_template.value = selected_template[2] # Set the current template to the selected name
50
+ return (
51
+ selected_template[2], # Name
52
+ selected_template[3], # Subject
53
+ selected_template[4], # Content
54
+ selected_template[5], # Sender Profile
55
+ selected_template[6], # Receiver Profile
56
+ )
57
+ return [gr.update() for _ in range(5)]
58
+
59
+ def delete_template(evt: gr.SelectData):
60
+ if evt.value:
61
+ template_id = templates_list.value[evt.index[0]][1]
62
+ delete_template_from_sheet(template_sheet, template_id)
63
+ return get_templates(template_sheet)
64
+ return templates_list.value
65
+
66
+ save_template_btn.click(save_template_action, outputs=[templates_list])
67
+ load_template_btn.click(load_template, outputs=[name, subject, content, sender_profile, receiver_profile])
68
+ delete_template_btn.click(delete_template, outputs=[templates_list])
69
+
70
+ refresh_btn = gr.Button("Refresh Templates")
71
+ refresh_btn.click(lambda: get_templates(template_sheet), outputs=[templates_list])
72
+
73
+ return name, subject, content, sender_profile, receiver_profile, save_draft_btn, save_template_btn, templates_list, load_template_btn, delete_template_btn, refresh_btn
74
+
75
+ # Implement create_template, update_template, delete_template functions
76
+ def create_template(sheet, name, subject, content, sender_profile, receiver_profile):
77
+ template_data = {
78
+ "name": name,
79
+ "subject": subject,
80
+ "content": content,
81
+ "sender_profile": sender_profile,
82
+ "receiver_profile": receiver_profile
83
+ }
84
+ return save_template(sheet, template_data)
85
+
86
+ def update_template(sheet, template_id, name, subject, content, sender_profile, receiver_profile):
87
+ template_data = {
88
+ "id": template_id,
89
+ "name": name,
90
+ "subject": subject,
91
+ "content": content,
92
+ "sender_profile": sender_profile,
93
+ "receiver_profile": receiver_profile
94
+ }
95
+ return save_template(sheet, template_data)
96
+
97
+ def delete_template(sheet, template_id):
98
+ return delete_template_from_sheet(sheet, template_id)
google_sheets_utils.py ADDED
@@ -0,0 +1,144 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # google_sheets_utils.py
2
+ # Filepath: ai-email-assistant/google_sheets_utils.py
3
+ # Manages interactions with Google Sheets for profile and template storage
4
+
5
+ import os
6
+ import json
7
+ import gspread
8
+ from google.oauth2.service_account import Credentials
9
+ import logging
10
+
11
+ # Set up logging
12
+ logging.basicConfig(level=logging.INFO)
13
+ logger = logging.getLogger(__name__)
14
+
15
+ def load_config():
16
+ with open('config.json', 'r') as f:
17
+ return json.load(f)
18
+
19
+ # Setup Google Sheets connection
20
+ SCOPES = ['https://www.googleapis.com/auth/spreadsheets',
21
+ 'https://www.googleapis.com/auth/drive']
22
+ config = load_config()
23
+ creds_file = config.get('google_sheets_credentials_file')
24
+ creds = Credentials.from_service_account_file(creds_file, scopes=SCOPES)
25
+ client = gspread.authorize(creds)
26
+
27
+ # Open the Google Sheet (create it if it doesn't exist)
28
+ try:
29
+ spreadsheet = client.open("AI Email Assistant")
30
+ logger.info("Successfully opened the spreadsheet.")
31
+ except gspread.exceptions.SpreadsheetNotFound:
32
+ logger.info("Spreadsheet 'AI Email Assistant' not found. Creating a new one.")
33
+ spreadsheet = client.create("AI Email Assistant")
34
+ logger.info("New spreadsheet 'AI Email Assistant' created.")
35
+
36
+ def initialize_sheet(sheet, headers, sample_data):
37
+ if not sheet.get_all_values():
38
+ sheet.append_row(headers)
39
+ for row in sample_data:
40
+ sheet.append_row(row)
41
+ logger.info(f"Initialized {sheet.title} with headers and sample data.")
42
+
43
+ def connect_to_sheets():
44
+ try:
45
+ sender_sheet = spreadsheet.worksheet("Sender Profiles")
46
+ except gspread.exceptions.WorksheetNotFound:
47
+ sender_sheet = spreadsheet.add_worksheet(title="Sender Profiles", rows="100", cols="20")
48
+
49
+ try:
50
+ receiver_sheet = spreadsheet.worksheet("Receiver Profiles")
51
+ except gspread.exceptions.WorksheetNotFound:
52
+ receiver_sheet = spreadsheet.add_worksheet(title="Receiver Profiles", rows="100", cols="20")
53
+
54
+ try:
55
+ template_sheet = spreadsheet.worksheet("Email Templates")
56
+ except gspread.exceptions.WorksheetNotFound:
57
+ template_sheet = spreadsheet.add_worksheet(title="Email Templates", rows="100", cols="20")
58
+
59
+ # Initialize sheets with headers and sample data if they're empty
60
+ profile_headers = ["Type", "ID", "Name", "Email", "Position", "Company", "Context"]
61
+ sender_sample = [
62
+ ["Sender", "SEND_1", "John Doe", "john@example.com", "Sales Manager", "ABC Corp", "Professional"],
63
+ ["Sender", "SEND_2", "Jane Smith", "jane@example.com", "Marketing Director", "XYZ Inc", "Professional"]
64
+ ]
65
+ receiver_sample = [
66
+ ["Receiver", "REC_1", "Alice Johnson", "alice@example.com", "CEO", "123 Industries", "Professional"],
67
+ ["Receiver", "REC_2", "Bob Brown", "bob@example.com", "HR Manager", "456 Corp", "Professional"]
68
+ ]
69
+ initialize_sheet(sender_sheet, profile_headers, sender_sample)
70
+ initialize_sheet(receiver_sheet, profile_headers, receiver_sample)
71
+
72
+ template_headers = ["Type", "ID", "Name", "Subject", "Content", "Sender Profile", "Receiver Profile"]
73
+ template_sample = [
74
+ ["Template", "TEMP_1", "Sales Pitch", "Exciting Offer!", "Dear {receiver_name},\n\nWe have an exciting offer for {receiver_company}...", "John Doe", "Alice Johnson"],
75
+ ["Template", "TEMP_2", "Follow-up", "Following up on our meeting", "Hello {receiver_name},\n\nI hope this email finds you well. I wanted to follow up on our recent meeting...", "Jane Smith", "Bob Brown"]
76
+ ]
77
+ initialize_sheet(template_sheet, template_headers, template_sample)
78
+
79
+ logger.info("Successfully connected to all sheets.")
80
+ return sender_sheet, receiver_sheet, template_sheet
81
+
82
+ def get_profiles_from_sheet(sheet):
83
+ data = sheet.get_all_values()
84
+ return data[1:] # Exclude header row
85
+
86
+ def save_profile(sheet, profile_data):
87
+ new_row = [
88
+ "Profile",
89
+ f"PROF_{sheet.row_count}",
90
+ profile_data['name'],
91
+ profile_data['email'],
92
+ profile_data['position'],
93
+ profile_data['company'],
94
+ profile_data['context']
95
+ ]
96
+ sheet.append_row(new_row)
97
+
98
+ def delete_profile_from_sheet(sheet, profile_id):
99
+ cell = sheet.find(profile_id)
100
+ if cell:
101
+ sheet.delete_row(cell.row)
102
+
103
+ def update_profile(sheet, profile_id, profile_data):
104
+ cell = sheet.find(profile_id)
105
+ if cell:
106
+ row = cell.row
107
+ sheet.update_cell(row, 3, profile_data['name'])
108
+ sheet.update_cell(row, 4, profile_data['email'])
109
+ sheet.update_cell(row, 5, profile_data['position'])
110
+ sheet.update_cell(row, 6, profile_data['company'])
111
+ sheet.update_cell(row, 7, profile_data['context'])
112
+
113
+ def get_templates(sheet):
114
+ data = sheet.get_all_values()
115
+ return data[1:] # Exclude header row
116
+
117
+ def save_template(sheet, template_data):
118
+ new_row = [
119
+ "Template",
120
+ f"TEMP_{sheet.row_count}",
121
+ template_data['name'],
122
+ template_data['subject'],
123
+ template_data['content'],
124
+ template_data['sender_profile'],
125
+ template_data['receiver_profile']
126
+ ]
127
+ sheet.append_row(new_row)
128
+
129
+ def delete_template_from_sheet(sheet, template_id):
130
+ cell = sheet.find(template_id)
131
+ if cell:
132
+ sheet.delete_row(cell.row)
133
+ return True
134
+ return False
135
+
136
+ def update_template(sheet, template_id, template_data):
137
+ cell = sheet.find(template_id)
138
+ if cell:
139
+ row = cell.row
140
+ sheet.update_cell(row, 3, template_data['name'])
141
+ sheet.update_cell(row, 4, template_data['subject'])
142
+ sheet.update_cell(row, 5, template_data['content'])
143
+ sheet.update_cell(row, 6, template_data['sender_profile'])
144
+ sheet.update_cell(row, 7, template_data['receiver_profile'])
groq_client.py ADDED
@@ -0,0 +1,43 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # groq_client.py
2
+ # Filepath: ai-email-assistant/groq_client.py
3
+ # Interfaces with the Groq API for AI-powered responses
4
+
5
+ import os
6
+ import json
7
+ from groq import Groq
8
+
9
+ def load_config():
10
+ try:
11
+ with open('config.json', 'r') as f:
12
+ return json.load(f)
13
+ except FileNotFoundError:
14
+ return {}
15
+
16
+ config = load_config()
17
+ api_key = config.get('groq_api_key')
18
+ client = Groq(api_key=api_key) if api_key else None
19
+
20
+ def set_api_key(api_key):
21
+ global client
22
+ client = Groq(api_key=api_key)
23
+
24
+ def get_ai_response(message, system_prompt, context=""):
25
+ if not client:
26
+ raise ValueError("Groq API key not set. Please check your config.json file.")
27
+
28
+ messages = [
29
+ {"role": "system", "content": system_prompt},
30
+ {"role": "user", "content": message}
31
+ ]
32
+
33
+ if context:
34
+ messages.append({"role": "system", "content": context})
35
+
36
+ response = client.chat.completions.create(
37
+ model="mixtral-8x7b-32768",
38
+ messages=messages,
39
+ temperature=0.7,
40
+ max_tokens=1000
41
+ )
42
+
43
+ return response.choices[0].message.content
profile_management.py ADDED
@@ -0,0 +1,100 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # profile_management.py
2
+ # Filepath: ai-email-assistant/profile_management.py
3
+ # Handles sender and receiver profile management
4
+
5
+ import gradio as gr
6
+ from google_sheets_utils import get_profiles_from_sheet, save_profile, delete_profile_from_sheet
7
+
8
+ def get_profile_summaries(sheet):
9
+ profiles = get_profiles_from_sheet(sheet)
10
+ return [profile[2] for profile in profiles] # Assuming the name is in the third column
11
+
12
+ def create_profile_management_interface(sheet, profile_type, current_profile):
13
+ with gr.Group():
14
+ gr.Markdown(f"## {profile_type} Profile Management")
15
+
16
+ name = gr.Textbox(label="Name")
17
+ email = gr.Textbox(label="Email")
18
+ position = gr.Textbox(label="Position")
19
+ company = gr.Textbox(label="Company")
20
+ context = gr.Dropdown(["Professional", "Personal"], label="Context")
21
+
22
+ create_btn = gr.Button(f"Create {profile_type} Profile")
23
+
24
+ profiles_list = gr.Dataframe(
25
+ headers=["Type", "ID", "Name", "Email", "Position", "Company", "Context"],
26
+ label=f"Existing {profile_type} Profiles",
27
+ value=get_profiles_from_sheet(sheet),
28
+ interactive=False
29
+ )
30
+
31
+ delete_btn = gr.Button(f"Delete Selected {profile_type} Profile")
32
+ load_btn = gr.Button(f"Load Selected {profile_type} Profile")
33
+
34
+ def create_profile_action():
35
+ profile_data = {
36
+ "name": name.value,
37
+ "email": email.value,
38
+ "position": position.value,
39
+ "company": company.value,
40
+ "context": context.value
41
+ }
42
+ save_profile(sheet, profile_data)
43
+ return get_profiles_from_sheet(sheet)
44
+
45
+ def load_profile(evt: gr.SelectData):
46
+ if evt.value:
47
+ selected_profile = profiles_list.value[evt.index[0]]
48
+ current_profile.value = selected_profile[2] # Set the current profile to the selected name
49
+ return (
50
+ selected_profile[2], # Name
51
+ selected_profile[3], # Email
52
+ selected_profile[4], # Position
53
+ selected_profile[5], # Company
54
+ selected_profile[6], # Context
55
+ )
56
+ return [gr.update() for _ in range(5)]
57
+
58
+ def delete_profile(evt: gr.SelectData):
59
+ if evt.value:
60
+ profile_id = profiles_list.value[evt.index[0]][1]
61
+ delete_profile_from_sheet(sheet, profile_id)
62
+ return get_profiles_from_sheet(sheet)
63
+ return profiles_list.value
64
+
65
+ create_btn.click(create_profile_action, outputs=[profiles_list])
66
+ load_btn.click(load_profile, outputs=[name, email, position, company, context])
67
+ delete_btn.click(delete_profile, outputs=[profiles_list])
68
+
69
+ refresh_btn = gr.Button(f"Refresh {profile_type} Profiles")
70
+ refresh_btn.click(lambda: get_profiles_from_sheet(sheet), outputs=[profiles_list])
71
+
72
+ return name, email, position, company, context, create_btn, profiles_list, delete_btn, load_btn, refresh_btn
73
+
74
+ # Implement get_profiles, create_profile, update_profile, delete_profile functions
75
+ def get_profiles(sheet):
76
+ return get_profiles_from_sheet(sheet)
77
+
78
+ def create_profile(sheet, name, email, position, company, context):
79
+ profile_data = {
80
+ "name": name,
81
+ "email": email,
82
+ "position": position,
83
+ "company": company,
84
+ "context": context
85
+ }
86
+ return save_profile(sheet, profile_data)
87
+
88
+ def update_profile(sheet, profile_id, name, email, position, company, context):
89
+ profile_data = {
90
+ "id": profile_id,
91
+ "name": name,
92
+ "email": email,
93
+ "position": position,
94
+ "company": company,
95
+ "context": context
96
+ }
97
+ return save_profile(sheet, profile_data)
98
+
99
+ def delete_profile(sheet, profile_id):
100
+ return delete_profile_from_sheet(sheet, profile_id)
requirements (2).txt ADDED
@@ -0,0 +1,213 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #
2
+ # This file is autogenerated by pip-compile with Python 3.12
3
+ # by the following command:
4
+ #
5
+ # pip-compile
6
+ #
7
+ aiofiles==23.2.1
8
+ # via gradio
9
+ annotated-types==0.7.0
10
+ # via pydantic
11
+ anyio==4.6.0
12
+ # via
13
+ # gradio
14
+ # groq
15
+ # httpx
16
+ # starlette
17
+ cachetools==5.5.0
18
+ # via google-auth
19
+ certifi==2024.8.30
20
+ # via
21
+ # httpcore
22
+ # httpx
23
+ # requests
24
+ charset-normalizer==3.3.2
25
+ # via requests
26
+ click==8.1.7
27
+ # via
28
+ # duckduckgo-search
29
+ # typer
30
+ # uvicorn
31
+ colorama==0.4.6
32
+ # via
33
+ # click
34
+ # tqdm
35
+ contourpy==1.3.0
36
+ # via matplotlib
37
+ cycler==0.12.1
38
+ # via matplotlib
39
+ distro==1.9.0
40
+ # via groq
41
+ duckduckgo-search==6.2.12
42
+ # via -r requirements.in
43
+ fastapi==0.115.0
44
+ # via gradio
45
+ ffmpy==0.4.0
46
+ # via gradio
47
+ filelock==3.16.1
48
+ # via huggingface-hub
49
+ fonttools==4.53.1
50
+ # via matplotlib
51
+ fsspec==2024.9.0
52
+ # via
53
+ # gradio-client
54
+ # huggingface-hub
55
+ google-auth==2.35.0
56
+ # via
57
+ # -r requirements.in
58
+ # google-auth-oauthlib
59
+ # gspread
60
+ google-auth-oauthlib==1.2.1
61
+ # via gspread
62
+ gradio==4.44.0
63
+ # via -r requirements.in
64
+ gradio-client==1.3.0
65
+ # via gradio
66
+ groq==0.11.0
67
+ # via -r requirements.in
68
+ gspread==6.1.2
69
+ # via -r requirements.in
70
+ h11==0.14.0
71
+ # via
72
+ # httpcore
73
+ # uvicorn
74
+ httpcore==1.0.5
75
+ # via httpx
76
+ httpx==0.27.2
77
+ # via
78
+ # gradio
79
+ # gradio-client
80
+ # groq
81
+ huggingface-hub==0.25.1
82
+ # via
83
+ # gradio
84
+ # gradio-client
85
+ idna==3.10
86
+ # via
87
+ # anyio
88
+ # httpx
89
+ # requests
90
+ importlib-resources==6.4.5
91
+ # via gradio
92
+ jinja2==3.1.4
93
+ # via gradio
94
+ kiwisolver==1.4.7
95
+ # via matplotlib
96
+ markdown-it-py==3.0.0
97
+ # via rich
98
+ markupsafe==2.1.5
99
+ # via
100
+ # gradio
101
+ # jinja2
102
+ matplotlib==3.9.2
103
+ # via gradio
104
+ mdurl==0.1.2
105
+ # via markdown-it-py
106
+ numpy==2.1.1
107
+ # via
108
+ # contourpy
109
+ # gradio
110
+ # matplotlib
111
+ # pandas
112
+ oauthlib==3.2.2
113
+ # via requests-oauthlib
114
+ orjson==3.10.7
115
+ # via gradio
116
+ packaging==24.1
117
+ # via
118
+ # gradio
119
+ # gradio-client
120
+ # huggingface-hub
121
+ # matplotlib
122
+ pandas==2.2.3
123
+ # via gradio
124
+ pillow==10.4.0
125
+ # via
126
+ # gradio
127
+ # matplotlib
128
+ primp==0.6.2
129
+ # via duckduckgo-search
130
+ pyasn1==0.6.1
131
+ # via
132
+ # pyasn1-modules
133
+ # rsa
134
+ pyasn1-modules==0.4.1
135
+ # via google-auth
136
+ pydantic==2.9.2
137
+ # via
138
+ # fastapi
139
+ # gradio
140
+ # groq
141
+ pydantic-core==2.23.4
142
+ # via pydantic
143
+ pydub==0.25.1
144
+ # via gradio
145
+ pygments==2.18.0
146
+ # via rich
147
+ pyparsing==3.1.4
148
+ # via matplotlib
149
+ python-dateutil==2.9.0.post0
150
+ # via
151
+ # matplotlib
152
+ # pandas
153
+ python-dotenv==1.0.1
154
+ # via -r requirements.in
155
+ python-multipart==0.0.10
156
+ # via gradio
157
+ pytz==2024.2
158
+ # via pandas
159
+ pyyaml==6.0.2
160
+ # via
161
+ # gradio
162
+ # huggingface-hub
163
+ requests==2.32.3
164
+ # via
165
+ # huggingface-hub
166
+ # requests-oauthlib
167
+ requests-oauthlib==2.0.0
168
+ # via google-auth-oauthlib
169
+ rich==13.8.1
170
+ # via typer
171
+ rsa==4.9
172
+ # via google-auth
173
+ ruff==0.6.7
174
+ # via gradio
175
+ semantic-version==2.10.0
176
+ # via gradio
177
+ shellingham==1.5.4
178
+ # via typer
179
+ six==1.16.0
180
+ # via python-dateutil
181
+ sniffio==1.3.1
182
+ # via
183
+ # anyio
184
+ # groq
185
+ # httpx
186
+ starlette==0.38.6
187
+ # via fastapi
188
+ tomlkit==0.12.0
189
+ # via gradio
190
+ tqdm==4.66.5
191
+ # via huggingface-hub
192
+ typer==0.12.5
193
+ # via gradio
194
+ typing-extensions==4.12.2
195
+ # via
196
+ # fastapi
197
+ # gradio
198
+ # gradio-client
199
+ # groq
200
+ # huggingface-hub
201
+ # pydantic
202
+ # pydantic-core
203
+ # typer
204
+ tzdata==2024.1
205
+ # via pandas
206
+ urllib3==2.2.3
207
+ # via
208
+ # gradio
209
+ # requests
210
+ uvicorn==0.30.6
211
+ # via gradio
212
+ websockets==12.0
213
+ # via gradio-client
system_prompt.txt ADDED
@@ -0,0 +1,65 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ You are an AI-driven email assistant designed to help users generate and refine personalized emails for various scenarios, including professional and personal contexts. Your goal is to gather necessary information through natural conversation and then create tailored emails. Adapt your role based on the email type, switching between casual assistant and professional content generator as needed. Follow these guidelines:
2
+ 1. Initial Interaction:
3
+ - Greet the user warmly and briefly explain your purpose.
4
+ - Ask an open-ended question about the type of email they need help with.
5
+ - Example: "Hello! I'm here to help you craft the perfect email. What kind of email are you looking to write today?"
6
+ 2. Information Gathering:
7
+ - Based on the user's response, ask relevant follow-up questions to gather necessary details.
8
+ - Adapt your questions to various email scenarios, including:
9
+ a) Professional emails: sales pitch, follow-up, introduction, product launch, partnership proposal
10
+ b) Personal emails: friendly correspondence, family updates
11
+ c) Transactional emails: customer support, shipping information, order confirmation
12
+ d) Formal communications: complaint to a company, job application, resignation letter
13
+ - Keep questions concise and conversational.
14
+ - For professional emails, gather additional relevant information:
15
+ a) Sender's details: name, job title, company, industry
16
+ b) Recipient's details: name, job title, company (if known)
17
+ c) Specific purpose: e.g., introducing a new product, following up on a sales call
18
+ d) Key points: e.g., 3 main features of a product, unique selling propositions
19
+ e) Any prior communication or context
20
+ f) Call-to-action or desired outcome
21
+ - For personal or transactional emails, adjust questions accordingly to gather relevant details.
22
+ 3. Background Checklist:
23
+ - Maintain an internal checklist of essential information for different email types.
24
+ - Discreetly check off items as you gather information.
25
+ - If crucial information is missing, naturally work it into the conversation.
26
+ 4. Information Confirmation:
27
+ - Summarize the gathered information concisely.
28
+ - Ask if anything is missing or needs changing.
29
+ 5. Role Adaptation:
30
+ - Based on the email type, adapt your role:
31
+ a) For professional emails: Take on the role of a professional content generator. Use industry-specific language, maintain a formal tone, and focus on creating compelling, persuasive content.
32
+ b) For personal emails: Maintain a friendly, conversational tone and focus on personal details and emotional context.
33
+ c) For transactional emails: Adopt a clear, concise, and informative tone, ensuring all necessary details are included.
34
+ 6. Email Generation:
35
+ - Create a personalized draft based on the confirmed information and your adapted role.
36
+ - Ensure the email is appropriate for the specific scenario and recipient.
37
+ - For professional emails, incorporate:
38
+ a) A strong, attention-grabbing opening
39
+ b) Clear presentation of key points or features
40
+ c) Relevant data or statistics to support your message
41
+ d) A clear call-to-action
42
+ - For personal or transactional emails, focus on clarity, warmth, or informativeness as appropriate.
43
+ 7. Refinement and Feedback:
44
+ - Present the draft to the user.
45
+ - Ask for overall impressions and any specific areas needing adjustment.
46
+ - Offer to make changes based on feedback.
47
+ 8. Iterative Improvement:
48
+ - Make requested adjustments promptly.
49
+ - Continue refining until the user is satisfied.
50
+ 9. Final Touches:
51
+ - Suggest additions like professional signatures, legal disclaimers, or attachment reminders if appropriate.
52
+ - Perform a final check for clarity, grammar, coherence, and appropriateness for the intended audience.
53
+ 10. Completion and Next Steps:
54
+ - Present the final version.
55
+ - Offer to save as a template or start a new email if needed.
56
+ 11. Adaptability:
57
+ - Remember user preferences within the session.
58
+ - Adjust your approach based on the user's communication style and the email context.
59
+ 12. Clarity and Error Handling:
60
+ - If confused, ask for clarification naturally.
61
+ - Guide users clearly if they seem unsure about the process.
62
+ 13. Privacy Reminder:
63
+ - Tactfully remind users not to share sensitive personal information.
64
+ - Mention that information isn't stored between sessions.
65
+ Always aim for clear, relevant, and engaging responses. Adapt your personality and language to match the user's tone and the email's purpose. Your goal is to make the email creation process smooth, efficient, and tailored to each unique situation, whether it's a high-stakes professional communication or a casual personal message.
web_search.py ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # web_search.py
2
+ # Filepath: ai-email-assistant/web_search.py
3
+ # Implements web search functionality
4
+
5
+ from duckduckgo_search import DDGS
6
+
7
+ def search_web(query, num_results=5):
8
+ try:
9
+ with DDGS() as ddgs:
10
+ results = list(ddgs.text(query, max_results=num_results))
11
+ return [f"{r['title']}: {r['body']}" for r in results]
12
+ except Exception as e:
13
+ return [f"Error performing web search: {str(e)}"]