abhlash commited on
Commit
fede037
·
1 Parent(s): 76b265a

updated the app

Browse files
Files changed (1) hide show
  1. app.py +163 -49
app.py CHANGED
@@ -3,18 +3,19 @@ from transformers import AutoTokenizer, AutoModelForCausalLM, LlamaConfig
3
  import os
4
  from dotenv import load_dotenv
5
  import logging
6
- import sys # Ensure sys is imported
7
  from huggingface_hub import login, HfApi
8
  import torch
9
 
10
  # Load environment variables
11
  load_dotenv()
 
 
12
  logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s', stream=sys.stdout)
13
 
14
  # Authenticate with Hugging Face
15
  hf_token = os.environ.get("HUGGINGFACE_TOKEN")
16
  model_name = "meta-llama/Llama-3.1-8B"
17
- fallback_model = "facebook/opt-350m"
18
 
19
  if hf_token:
20
  try:
@@ -24,49 +25,107 @@ if hf_token:
24
  logging.info("Successfully logged in to Hugging Face")
25
  except Exception as e:
26
  logging.error(f"Error authenticating with Hugging Face: {str(e)}")
27
- logging.warning("Proceeding without authentication. Will use fallback model.")
28
- model_name = fallback_model
29
  else:
30
  logging.warning("HUGGINGFACE_TOKEN not found in environment variables. Proceeding without authentication.")
31
- model_name = fallback_model
32
 
33
  # Load the model and tokenizer
34
  try:
 
35
  tokenizer = AutoTokenizer.from_pretrained(model_name)
 
 
 
 
 
36
 
37
- # Custom configuration to handle the RoPE scaling issue
38
- if model_name == "meta-llama/Llama-3.1-8B":
39
- config = LlamaConfig.from_pretrained(model_name)
40
- config.rope_scaling = {"type": "linear", "factor": 8.0} # Adjust as needed
41
- model = AutoModelForCausalLM.from_pretrained(model_name, config=config)
42
- else:
43
- model = AutoModelForCausalLM.from_pretrained(model_name)
44
 
45
  logging.info(f"Successfully loaded {model_name}")
46
  except Exception as e:
47
  logging.error(f"Error loading {model_name}: {str(e)}")
48
- logging.info(f"Falling back to {fallback_model}")
49
- tokenizer = AutoTokenizer.from_pretrained(fallback_model)
50
- model = AutoModelForCausalLM.from_pretrained(fallback_model)
51
 
52
- def generate_email(recipient_name, recipient_email, industry, recipient_role, details):
53
- prompt = (
54
- f"Write a short professional email to {recipient_name}, "
55
- f"a {recipient_role} in the {industry} industry. "
56
- f"Mention: {details}. Keep it under 100 words."
57
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
58
  try:
59
- inputs = tokenizer(prompt, return_tensors="pt", padding=True, truncation=True, max_length=512)
60
 
61
- # Check if we're using CPU or GPU
62
  device = "cuda" if torch.cuda.is_available() else "cpu"
63
  model.to(device)
64
  inputs = {k: v.to(device) for k, v in inputs.items()}
65
 
66
  with torch.no_grad():
67
- outputs = model.generate(
68
  **inputs,
69
- max_length=200, # Reduced max length
70
  num_return_sequences=1,
71
  temperature=0.7,
72
  top_k=50,
@@ -74,34 +133,94 @@ def generate_email(recipient_name, recipient_email, industry, recipient_role, de
74
  do_sample=True
75
  )
76
 
77
- email_body = tokenizer.decode(outputs[0], skip_special_tokens=True)
78
- logging.info(f"Generated raw email body: {email_body}")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
79
 
80
- # Minimal cleaning
81
- email_body = email_body.strip()
82
- if not email_body:
83
- raise ValueError("Generated email body is empty")
84
 
85
- # Format the email
86
- formatted_email = f"""\
87
- To: {recipient_name} <{recipient_email}>
88
- Subject: Collaboration Opportunity
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
89
 
90
  {email_body}
91
 
92
- Best regards,
93
- Jane Smith
94
- Android Developer
95
- Albertsons
96
- [Your Contact Information]
 
 
 
 
97
  """
98
- return formatted_email
 
99
 
100
  except Exception as e:
101
- logging.error(f"Error generating email: {str(e)}")
102
  return f"Error generating email: {str(e)}"
103
 
104
- # Create Gradio interface
 
105
  iface = gr.Interface(
106
  fn=generate_email,
107
  inputs=[
@@ -109,17 +228,12 @@ iface = gr.Interface(
109
  gr.Textbox(lines=1, label="Recipient Email"),
110
  gr.Textbox(lines=1, label="Industry (e.g., Technology, Healthcare)"),
111
  gr.Textbox(lines=1, label="Recipient Role (e.g., Manager, Director)"),
112
- gr.Textbox(lines=5, label="Personal/Company Details (e.g., name, product)"),
113
  ],
114
  outputs=gr.Textbox(lines=10, label="Generated Email or Error Message"),
115
  title="EmailGenie: AI-Powered Email Generator",
116
  description="Automate the creation of personalized emails. Enter details to generate tailored emails."
117
  )
118
 
119
- # Launch the app
120
  if __name__ == '__main__':
121
  iface.launch()
122
-
123
- # Log model information
124
- logging.info(f"Model name: {model.config._name_or_path}")
125
- logging.info(f"Model parameters: {model.num_parameters()}")
 
3
  import os
4
  from dotenv import load_dotenv
5
  import logging
6
+ import sys
7
  from huggingface_hub import login, HfApi
8
  import torch
9
 
10
  # Load environment variables
11
  load_dotenv()
12
+
13
+ # Setup logging
14
  logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s', stream=sys.stdout)
15
 
16
  # Authenticate with Hugging Face
17
  hf_token = os.environ.get("HUGGINGFACE_TOKEN")
18
  model_name = "meta-llama/Llama-3.1-8B"
 
19
 
20
  if hf_token:
21
  try:
 
25
  logging.info("Successfully logged in to Hugging Face")
26
  except Exception as e:
27
  logging.error(f"Error authenticating with Hugging Face: {str(e)}")
28
+ logging.warning("Proceeding without authentication. This may limit access to certain models.")
 
29
  else:
30
  logging.warning("HUGGINGFACE_TOKEN not found in environment variables. Proceeding without authentication.")
 
31
 
32
  # Load the model and tokenizer
33
  try:
34
+ logging.info(f"Attempting to load tokenizer for {model_name}")
35
  tokenizer = AutoTokenizer.from_pretrained(model_name)
36
+ logging.info("Tokenizer loaded successfully")
37
+
38
+ logging.info(f"Attempting to load model {model_name}")
39
+ model = AutoModelForCausalLM.from_pretrained(model_name)
40
+ logging.info("Model loaded successfully")
41
 
42
+ if tokenizer.pad_token is None:
43
+ tokenizer.pad_token = tokenizer.eos_token
44
+ model.config.pad_token_id = model.config.eos_token_id
 
 
 
 
45
 
46
  logging.info(f"Successfully loaded {model_name}")
47
  except Exception as e:
48
  logging.error(f"Error loading {model_name}: {str(e)}")
49
+ raise
 
 
50
 
51
+ MAX_TOTAL_TOKENS = 2048 # Adjusted to Llama model's token limit
52
+ MAX_INPUT_TOKENS = 1600 # 1600 tokens for input, leaving room for generated output
53
+ CONTEXT_RATIO = 0.6 # Adjusted for summarization
54
+
55
+ def truncate_to_token_limit(text, max_tokens):
56
+ tokens = tokenizer.encode(text)
57
+ if len(tokens) > max_tokens:
58
+ tokens = tokens[:max_tokens]
59
+ return tokenizer.decode(tokens, skip_special_tokens=True)
60
+
61
+ def summarize_text(text, max_tokens):
62
+ if len(tokenizer.encode(text)) <= max_tokens:
63
+ return text, None
64
+
65
+ summarization_prompt = f"""
66
+ Summarize the following text concisely, preserving the key points:
67
+
68
+ {text}
69
+
70
+ Ensure the summary is under {max_tokens} tokens.
71
+ """
72
+
73
+ try:
74
+ inputs = tokenizer(summarization_prompt, return_tensors="pt", padding=True, truncation=True, max_length=int(MAX_INPUT_TOKENS * CONTEXT_RATIO))
75
+
76
+ device = "cuda" if torch.cuda.is_available() else "cpu"
77
+ model.to(device)
78
+ inputs = {k: v.to(device) for k, v in inputs.items()}
79
+
80
+ with torch.no_grad():
81
+ summary_outputs = model.generate(
82
+ **inputs,
83
+ max_new_tokens=max_tokens,
84
+ num_return_sequences=1,
85
+ temperature=0.7,
86
+ top_k=50,
87
+ top_p=0.95,
88
+ do_sample=True
89
+ )
90
+
91
+ summary = tokenizer.decode(summary_outputs[0], skip_special_tokens=True)
92
+ summary = summary.replace(summarization_prompt, "").strip()
93
+
94
+ warning = "Input was summarized to fit the token limit. Some details may be omitted."
95
+ return summary, warning
96
+ except Exception as e:
97
+ logging.error(f"Error during summarization: {str(e)}")
98
+ return text[:max_tokens] + "...", "Error in summarization. Text was truncated."
99
+
100
+ def generate_prompt(recipient_name, recipient_role, industry, details):
101
+ details, warning = summarize_text(details, MAX_INPUT_TOKENS // 2)
102
+
103
+ prompt_generation_input = f"""
104
+ Create a detailed prompt for writing a professional email based on the following information:
105
+ - Recipient: {recipient_name}, a {recipient_role} in the {industry} industry
106
+ - Purpose: {details}
107
+
108
+ Include:
109
+ 1. Greeting
110
+ 2. Main email points
111
+ 3. Suggested closing
112
+ 4. Tone (e.g., formal, friendly)
113
+ 5. Industry-relevant phrases or terms
114
+ """
115
+
116
+ prompt_generation_input = truncate_to_token_limit(prompt_generation_input, MAX_INPUT_TOKENS)
117
+
118
  try:
119
+ inputs = tokenizer(prompt_generation_input, return_tensors="pt", padding=True, truncation=True, max_length=MAX_INPUT_TOKENS)
120
 
 
121
  device = "cuda" if torch.cuda.is_available() else "cpu"
122
  model.to(device)
123
  inputs = {k: v.to(device) for k, v in inputs.items()}
124
 
125
  with torch.no_grad():
126
+ prompt_outputs = model.generate(
127
  **inputs,
128
+ max_new_tokens=200,
129
  num_return_sequences=1,
130
  temperature=0.7,
131
  top_k=50,
 
133
  do_sample=True
134
  )
135
 
136
+ generated_prompt = tokenizer.decode(prompt_outputs[0], skip_special_tokens=True)
137
+ return generated_prompt.replace(prompt_generation_input, "").strip(), warning
138
+
139
+ except Exception as e:
140
+ logging.error(f"Error generating prompt: {str(e)}")
141
+ return f"Error generating prompt: {str(e)}", None
142
+
143
+ def generate_email_body(prompt):
144
+ # Concise prompt without instruction language
145
+ email_generation_input = f"""
146
+ {prompt}
147
+ """
148
+
149
+ # Limit input to token constraints
150
+ email_generation_input = truncate_to_token_limit(email_generation_input, MAX_INPUT_TOKENS)
151
+
152
+ try:
153
+ inputs = tokenizer(email_generation_input, return_tensors="pt", padding=True, truncation=True, max_length=MAX_INPUT_TOKENS)
154
+
155
+ device = "cuda" if torch.cuda.is_available() else "cpu"
156
+ model.to(device)
157
+ inputs = {k: v.to(device) for k, v in inputs.items()}
158
+
159
+ with torch.no_grad():
160
+ email_outputs = model.generate(
161
+ **inputs,
162
+ max_new_tokens=300,
163
+ num_return_sequences=1,
164
+ temperature=0.5, # Lower temperature for more focused output
165
+ top_k=50,
166
+ top_p=0.95,
167
+ do_sample=False # Deterministic output
168
+ )
169
+
170
+ # Decode and return only the email body
171
+ email_body = tokenizer.decode(email_outputs[0], skip_special_tokens=True).strip()
172
+
173
+ return email_body
174
 
175
+ except Exception as e:
176
+ logging.error(f"Error generating email body: {str(e)}")
177
+ return f"Error generating email body: {str(e)}"
 
178
 
179
+ def generate_email(recipient_name, recipient_email, industry, recipient_role, details):
180
+ try:
181
+ # Clear, minimal prompt to keep focus on main content generation
182
+ generated_prompt = f"I am reaching out to discuss {details} in the context of {industry} and how it impacts your role as a {recipient_role}."
183
+
184
+ # Generate the email body
185
+ email_body = generate_email_body(generated_prompt)
186
+ if email_body.startswith("Error"):
187
+ return email_body
188
+
189
+ # Remove duplicate greetings and signatures if they appear
190
+ email_body_lines = email_body.splitlines()
191
+ unique_lines = []
192
+ for line in email_body_lines:
193
+ if line.strip() and line not in unique_lines:
194
+ unique_lines.append(line)
195
+ email_body = "\n".join(unique_lines)
196
+
197
+ # Assemble the final email content
198
+ final_output = f"""
199
+ Subject: {details.split()[0].capitalize()} Proposal
200
+
201
+ Dear {recipient_name},
202
 
203
  {email_body}
204
 
205
+ Sincerely,
206
+ Your Name
207
+ Your Title
208
+ Your Company
209
+ Your Email
210
+ Your Phone Number
211
+ Your Address
212
+ Your Website
213
+ Your Social Media Profiles
214
  """
215
+ logging.info(f"Final email content:\n{final_output}")
216
+ return final_output
217
 
218
  except Exception as e:
219
+ logging.error(f"Error in generate_email: {str(e)}")
220
  return f"Error generating email: {str(e)}"
221
 
222
+
223
+
224
  iface = gr.Interface(
225
  fn=generate_email,
226
  inputs=[
 
228
  gr.Textbox(lines=1, label="Recipient Email"),
229
  gr.Textbox(lines=1, label="Industry (e.g., Technology, Healthcare)"),
230
  gr.Textbox(lines=1, label="Recipient Role (e.g., Manager, Director)"),
231
+ gr.Textbox(lines=5, label="Personal/Company Details"),
232
  ],
233
  outputs=gr.Textbox(lines=10, label="Generated Email or Error Message"),
234
  title="EmailGenie: AI-Powered Email Generator",
235
  description="Automate the creation of personalized emails. Enter details to generate tailored emails."
236
  )
237
 
 
238
  if __name__ == '__main__':
239
  iface.launch()