Spaces:
Running
Running
slight fixes
Browse files
app.py
CHANGED
@@ -51,43 +51,105 @@ def load_modules():
|
|
51 |
return None, None
|
52 |
|
53 |
def create_fallback_email(name, company, tone="professional"):
|
54 |
-
"""Create a high-quality fallback email when AI fails"""
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
55 |
if tone.lower() == "friendly":
|
56 |
-
|
57 |
-
|
|
|
|
|
|
|
|
|
|
|
58 |
|
59 |
Just came across {company} and really impressed with your work!
|
60 |
|
61 |
-
We've helped similar companies increase their efficiency by 40%. Mind if I share a quick example?
|
62 |
|
63 |
Worth a 15-minute chat?
|
64 |
|
65 |
Cheers,
|
66 |
-
Alex"""
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
67 |
elif tone.lower() == "direct":
|
68 |
-
|
69 |
-
|
|
|
|
|
|
|
|
|
|
|
70 |
|
71 |
Quick question: Is {company} looking to reduce operational costs?
|
72 |
|
73 |
-
We just helped a similar company save $50K annually with simple automation.
|
74 |
|
75 |
Worth a 10-minute call?
|
76 |
|
77 |
Best,
|
78 |
-
Sarah"""
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
79 |
else: # professional
|
80 |
-
|
81 |
-
|
|
|
|
|
|
|
|
|
|
|
82 |
|
83 |
-
I noticed {company}'s work in
|
84 |
|
85 |
We recently helped a similar organization achieve 35% operational cost reduction through process optimization.
|
86 |
|
87 |
Would you be open to a brief conversation about how this might apply to {company}?
|
88 |
|
89 |
Best regards,
|
90 |
-
Michael Thompson"""
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
91 |
|
92 |
return {
|
93 |
'subject': subject,
|
@@ -162,9 +224,27 @@ def process_leads(df, tone, creativity):
|
|
162 |
print(f"AI generation failed for {row['name']}: {e}")
|
163 |
email_result = None
|
164 |
|
165 |
-
# Use fallback if AI failed
|
166 |
if not email_result or not email_result.get('content'):
|
167 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
168 |
|
169 |
# Create result
|
170 |
result = {
|
@@ -183,16 +263,46 @@ def process_leads(df, tone, creativity):
|
|
183 |
except Exception as e:
|
184 |
st.warning(f"β οΈ Issue with {row['name']}: {str(e)}")
|
185 |
# Always create a result, even with errors
|
186 |
-
|
187 |
-
|
188 |
-
|
189 |
-
|
190 |
-
|
191 |
-
|
192 |
-
|
193 |
-
|
194 |
-
|
195 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
196 |
results.append(result)
|
197 |
|
198 |
progress_bar.progress(1.0)
|
@@ -312,52 +422,115 @@ def main():
|
|
312 |
high_quality = len([r for r in results if r['quality_score'] >= 8.0])
|
313 |
st.metric("β High Quality", high_quality)
|
314 |
|
315 |
-
# Results table
|
316 |
st.subheader("π Generated Emails")
|
317 |
-
|
318 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
319 |
|
320 |
-
# Email preview
|
321 |
st.subheader("π Email Preview")
|
322 |
-
|
323 |
-
|
324 |
-
|
325 |
-
|
326 |
-
|
327 |
-
|
328 |
-
|
329 |
-
|
330 |
-
|
331 |
-
|
332 |
-
|
333 |
-
|
334 |
-
|
335 |
-
|
336 |
-
|
337 |
-
|
338 |
-
|
339 |
-
|
340 |
-
|
341 |
-
|
342 |
-
|
343 |
-
|
344 |
-
|
345 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
346 |
|
347 |
-
# Export
|
348 |
st.subheader("π€ Export Results")
|
349 |
-
|
350 |
-
|
351 |
-
|
352 |
-
|
353 |
-
|
354 |
-
|
355 |
-
|
356 |
-
|
357 |
-
|
358 |
-
|
359 |
-
|
360 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
361 |
|
362 |
else:
|
363 |
st.error("β Failed to generate emails. Please try again.")
|
|
|
51 |
return None, None
|
52 |
|
53 |
def create_fallback_email(name, company, tone="professional"):
|
54 |
+
"""Create a high-quality personalized fallback email when AI fails"""
|
55 |
+
import random
|
56 |
+
|
57 |
+
# Industry detection for better personalization
|
58 |
+
if any(word in company.lower() for word in ['tech', 'software', 'digital', 'ai', 'data']):
|
59 |
+
industry = "technology"
|
60 |
+
elif any(word in company.lower() for word in ['health', 'medical', 'pharma']):
|
61 |
+
industry = "healthcare"
|
62 |
+
elif any(word in company.lower() for word in ['financ', 'bank', 'invest']):
|
63 |
+
industry = "financial"
|
64 |
+
else:
|
65 |
+
industry = "general"
|
66 |
+
|
67 |
if tone.lower() == "friendly":
|
68 |
+
subjects = [
|
69 |
+
f"Love what {company} is doing!",
|
70 |
+
f"Impressed by {company}'s work",
|
71 |
+
f"Quick collaboration idea for {company}"
|
72 |
+
]
|
73 |
+
bodies = [
|
74 |
+
f"""Hi {name},
|
75 |
|
76 |
Just came across {company} and really impressed with your work!
|
77 |
|
78 |
+
We've helped similar {industry} companies increase their efficiency by 40%. Mind if I share a quick example?
|
79 |
|
80 |
Worth a 15-minute chat?
|
81 |
|
82 |
Cheers,
|
83 |
+
Alex""",
|
84 |
+
f"""Hey {name},
|
85 |
+
|
86 |
+
{company} caught my attention - love what you're building!
|
87 |
+
|
88 |
+
We just helped another {industry} company streamline their operations. The results were pretty impressive.
|
89 |
+
|
90 |
+
Open to a quick conversation?
|
91 |
+
|
92 |
+
Best,
|
93 |
+
Sam"""
|
94 |
+
]
|
95 |
elif tone.lower() == "direct":
|
96 |
+
subjects = [
|
97 |
+
f"Quick ROI opportunity for {company}",
|
98 |
+
f"{company} + cost reduction?",
|
99 |
+
f"15% efficiency gain for {company}?"
|
100 |
+
]
|
101 |
+
bodies = [
|
102 |
+
f"""{name},
|
103 |
|
104 |
Quick question: Is {company} looking to reduce operational costs?
|
105 |
|
106 |
+
We just helped a similar {industry} company save $50K annually with simple automation.
|
107 |
|
108 |
Worth a 10-minute call?
|
109 |
|
110 |
Best,
|
111 |
+
Sarah""",
|
112 |
+
f"""{name},
|
113 |
+
|
114 |
+
Straight to the point: We reduced costs by 25% for a {industry} company last month.
|
115 |
+
|
116 |
+
Interested in hearing how this applies to {company}?
|
117 |
+
|
118 |
+
10-minute call?
|
119 |
+
|
120 |
+
-Mike"""
|
121 |
+
]
|
122 |
else: # professional
|
123 |
+
subjects = [
|
124 |
+
f"Operational efficiency opportunity - {company}",
|
125 |
+
f"Thought on {company}'s growth",
|
126 |
+
f"Strategic partnership inquiry - {company}"
|
127 |
+
]
|
128 |
+
bodies = [
|
129 |
+
f"""Hi {name},
|
130 |
|
131 |
+
I noticed {company}'s work in the {industry} space and wanted to reach out with a potential opportunity.
|
132 |
|
133 |
We recently helped a similar organization achieve 35% operational cost reduction through process optimization.
|
134 |
|
135 |
Would you be open to a brief conversation about how this might apply to {company}?
|
136 |
|
137 |
Best regards,
|
138 |
+
Michael Thompson""",
|
139 |
+
f"""Hi {name},
|
140 |
+
|
141 |
+
Hope this finds you well. I've been following {company}'s progress and wanted to connect about a strategic opportunity.
|
142 |
+
|
143 |
+
We've developed solutions that help {industry} companies scale efficiently while reducing overhead.
|
144 |
+
|
145 |
+
Would you be interested in a 15-minute discussion?
|
146 |
+
|
147 |
+
Best regards,
|
148 |
+
Jennifer Chen"""
|
149 |
+
]
|
150 |
+
|
151 |
+
subject = random.choice(subjects)
|
152 |
+
body = random.choice(bodies)
|
153 |
|
154 |
return {
|
155 |
'subject': subject,
|
|
|
224 |
print(f"AI generation failed for {row['name']}: {e}")
|
225 |
email_result = None
|
226 |
|
227 |
+
# Use advanced fallback if AI failed
|
228 |
if not email_result or not email_result.get('content'):
|
229 |
+
if email_generator:
|
230 |
+
try:
|
231 |
+
# Use the email generator's advanced fallback system
|
232 |
+
subject, body = email_generator._advanced_fallback_generation(
|
233 |
+
row['name'],
|
234 |
+
row['company'],
|
235 |
+
company_data,
|
236 |
+
tone
|
237 |
+
)
|
238 |
+
email_result = {
|
239 |
+
'subject': subject,
|
240 |
+
'content': body,
|
241 |
+
'quality_score': 8.5
|
242 |
+
}
|
243 |
+
except:
|
244 |
+
# Final fallback
|
245 |
+
email_result = create_fallback_email(row['name'], row['company'], tone)
|
246 |
+
else:
|
247 |
+
email_result = create_fallback_email(row['name'], row['company'], tone)
|
248 |
|
249 |
# Create result
|
250 |
result = {
|
|
|
263 |
except Exception as e:
|
264 |
st.warning(f"β οΈ Issue with {row['name']}: {str(e)}")
|
265 |
# Always create a result, even with errors
|
266 |
+
if email_generator:
|
267 |
+
try:
|
268 |
+
fallback_result = email_generator._advanced_fallback_generation(
|
269 |
+
row['name'],
|
270 |
+
row['company'],
|
271 |
+
'',
|
272 |
+
tone
|
273 |
+
)
|
274 |
+
result = {
|
275 |
+
'name': row['name'],
|
276 |
+
'email': row['email'],
|
277 |
+
'company': row['company'],
|
278 |
+
'subject': fallback_result[0],
|
279 |
+
'email_content': fallback_result[1],
|
280 |
+
'quality_score': 8.0,
|
281 |
+
'status': 'fallback'
|
282 |
+
}
|
283 |
+
except:
|
284 |
+
fallback_result = create_fallback_email(row['name'], row['company'], tone)
|
285 |
+
result = {
|
286 |
+
'name': row['name'],
|
287 |
+
'email': row['email'],
|
288 |
+
'company': row['company'],
|
289 |
+
'subject': fallback_result.get('subject', f"Partnership Opportunity - {row['company']}"),
|
290 |
+
'email_content': fallback_result.get('content', ''),
|
291 |
+
'quality_score': 7.0,
|
292 |
+
'status': 'error'
|
293 |
+
}
|
294 |
+
else:
|
295 |
+
fallback_result = create_fallback_email(row['name'], row['company'], tone)
|
296 |
+
result = {
|
297 |
+
'name': row['name'],
|
298 |
+
'email': row['email'],
|
299 |
+
'company': row['company'],
|
300 |
+
'subject': fallback_result.get('subject', f"Partnership Opportunity - {row['company']}"),
|
301 |
+
'email_content': fallback_result.get('content', ''),
|
302 |
+
'quality_score': 7.0,
|
303 |
+
'status': 'basic_fallback'
|
304 |
+
}
|
305 |
+
|
306 |
results.append(result)
|
307 |
|
308 |
progress_bar.progress(1.0)
|
|
|
422 |
high_quality = len([r for r in results if r['quality_score'] >= 8.0])
|
423 |
st.metric("β High Quality", high_quality)
|
424 |
|
425 |
+
# Results table with data validation
|
426 |
st.subheader("π Generated Emails")
|
427 |
+
try:
|
428 |
+
# Clean and validate results data before display
|
429 |
+
clean_results = []
|
430 |
+
for r in results:
|
431 |
+
# Ensure all values are strings and properly sanitized
|
432 |
+
clean_result = {
|
433 |
+
'name': str(r.get('name', 'Unknown')).replace('\n', ' ').replace('\r', '')[:50],
|
434 |
+
'company': str(r.get('company', 'Unknown')).replace('\n', ' ').replace('\r', '')[:50],
|
435 |
+
'subject': str(r.get('subject', 'No subject')).replace('\n', ' ').replace('\r', '')[:80],
|
436 |
+
'quality_score': round(float(r.get('quality_score', 8.0)), 1)
|
437 |
+
}
|
438 |
+
# Validate that quality score is within range
|
439 |
+
if clean_result['quality_score'] < 1.0 or clean_result['quality_score'] > 10.0:
|
440 |
+
clean_result['quality_score'] = 8.0
|
441 |
+
clean_results.append(clean_result)
|
442 |
+
|
443 |
+
display_df = pd.DataFrame(clean_results)
|
444 |
+
# Ensure DataFrame has the expected columns
|
445 |
+
expected_columns = ['name', 'company', 'subject', 'quality_score']
|
446 |
+
for col in expected_columns:
|
447 |
+
if col not in display_df.columns:
|
448 |
+
display_df[col] = 'N/A'
|
449 |
+
|
450 |
+
st.dataframe(display_df[expected_columns], use_container_width=True, height=300)
|
451 |
+
except Exception as e:
|
452 |
+
st.warning("β οΈ Display issue - showing simplified view")
|
453 |
+
simple_data = [[r['name'], r['company'], f"{r['quality_score']:.1f}"] for r in results]
|
454 |
+
st.table(pd.DataFrame(simple_data, columns=['Name', 'Company', 'Quality']))
|
455 |
|
456 |
+
# Email preview with error handling
|
457 |
st.subheader("π Email Preview")
|
458 |
+
try:
|
459 |
+
if len(results) > 0:
|
460 |
+
selected_idx = st.selectbox(
|
461 |
+
"Select email to preview:",
|
462 |
+
range(min(len(results), 50)), # Limit to prevent crashes
|
463 |
+
format_func=lambda x: f"{results[x]['name']} - {results[x]['company']} (Q: {results[x]['quality_score']:.1f})"
|
464 |
+
)
|
465 |
+
|
466 |
+
if selected_idx < len(results):
|
467 |
+
selected_email = results[selected_idx]
|
468 |
+
|
469 |
+
col1, col2 = st.columns([1, 1])
|
470 |
+
with col1:
|
471 |
+
st.write("**π§ Subject:**")
|
472 |
+
# Ensure subject is clean and safe for display
|
473 |
+
clean_subject = str(selected_email.get('subject', 'No subject'))
|
474 |
+
clean_subject = clean_subject.replace('\n', ' ').replace('\r', '')[:150]
|
475 |
+
st.code(clean_subject)
|
476 |
+
st.write("**π Quality Score:**")
|
477 |
+
quality = float(selected_email.get('quality_score', 8.0))
|
478 |
+
# Ensure quality is in valid range
|
479 |
+
quality = max(1.0, min(10.0, quality))
|
480 |
+
st.metric("", f"{quality:.1f}/10")
|
481 |
+
|
482 |
+
with col2:
|
483 |
+
st.write("**π Email Content:**")
|
484 |
+
# Ensure content is clean and safe for display
|
485 |
+
clean_content = str(selected_email.get('email_content', 'No content'))
|
486 |
+
# Remove problematic characters that might cause React errors
|
487 |
+
clean_content = clean_content.replace('\r\n', '\n').replace('\r', '\n')
|
488 |
+
# Limit length to prevent display issues
|
489 |
+
clean_content = clean_content[:2000]
|
490 |
+
st.text_area(
|
491 |
+
"",
|
492 |
+
clean_content,
|
493 |
+
height=250,
|
494 |
+
disabled=True,
|
495 |
+
label_visibility="collapsed"
|
496 |
+
)
|
497 |
+
except Exception as e:
|
498 |
+
st.error("β οΈ Preview unavailable - but your emails were generated successfully")
|
499 |
|
500 |
+
# Export with data validation
|
501 |
st.subheader("π€ Export Results")
|
502 |
+
try:
|
503 |
+
# Clean export data with robust validation
|
504 |
+
export_data = []
|
505 |
+
for r in results:
|
506 |
+
# Sanitize all data for CSV export
|
507 |
+
clean_row = {
|
508 |
+
'name': str(r.get('name', 'Unknown')).strip()[:100],
|
509 |
+
'email': str(r.get('email', '[email protected]')).strip()[:100],
|
510 |
+
'company': str(r.get('company', 'Unknown')).strip()[:100],
|
511 |
+
'subject': str(r.get('subject', 'No subject')).replace('\n', ' ').replace('\r', ' ').strip()[:200],
|
512 |
+
'email_content': str(r.get('email_content', 'No content')).replace('\r\n', '\n').replace('\r', '\n').strip()[:5000],
|
513 |
+
'quality_score': round(max(1.0, min(10.0, float(r.get('quality_score', 8.0)))), 1),
|
514 |
+
'status': str(r.get('status', 'success')).strip()[:20]
|
515 |
+
}
|
516 |
+
export_data.append(clean_row)
|
517 |
+
|
518 |
+
export_df = pd.DataFrame(export_data)
|
519 |
+
# Ensure no NaN values that could cause issues
|
520 |
+
export_df = export_df.fillna('')
|
521 |
+
csv_data = export_df.to_csv(index=False, encoding='utf-8').encode('utf-8')
|
522 |
+
|
523 |
+
st.download_button(
|
524 |
+
"π₯ Download All Emails (CSV)",
|
525 |
+
csv_data,
|
526 |
+
f"cold_emails_{datetime.now().strftime('%Y%m%d_%H%M%S')}.csv",
|
527 |
+
"text/csv",
|
528 |
+
use_container_width=True
|
529 |
+
)
|
530 |
+
|
531 |
+
st.info(f"π‘ Ready to export {len(results)} professional cold emails for your outreach campaign!")
|
532 |
+
except Exception as e:
|
533 |
+
st.error("β οΈ Export issue - please try regenerating")
|
534 |
|
535 |
else:
|
536 |
st.error("β Failed to generate emails. Please try again.")
|