selva1909 commited on
Commit
4a6b3ed
·
verified ·
1 Parent(s): 2858f58

Upload 3 files

Browse files
Files changed (3) hide show
  1. app.py +244 -0
  2. requirements.txt +8 -0
  3. token.pickle +3 -0
app.py ADDED
@@ -0,0 +1,244 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import base64
3
+ import mimetypes
4
+ import requests
5
+ import gradio as gr
6
+ from email.message import EmailMessage
7
+ from pathlib import Path
8
+ from dotenv import load_dotenv
9
+ from google.auth.transport.requests import Request
10
+ from google_auth_oauthlib.flow import InstalledAppFlow
11
+ from googleapiclient.discovery import build
12
+ import pickle
13
+
14
+ # ---------- Load environment variables ----------
15
+ load_dotenv()
16
+ OPENROUTER_API_KEY = os.getenv("OPENROUTER_API_KEY", "")
17
+ OPENROUTER_URL = "https://openrouter.ai/api/v1/chat/completions"
18
+
19
+ # Gmail API setup
20
+ SCOPES = ['https://www.googleapis.com/auth/gmail.send']
21
+ CREDENTIALS_FILE = 'credentials.json'
22
+ TOKEN_FILE = 'token.pickle'
23
+
24
+
25
+ # ---------- Gmail Authentication ----------
26
+ def authenticate_gmail():
27
+ creds = None
28
+ if os.path.exists(TOKEN_FILE):
29
+ with open(TOKEN_FILE, 'rb') as token:
30
+ creds = pickle.load(token)
31
+ if not creds or not creds.valid:
32
+ if creds and creds.expired and creds.refresh_token:
33
+ creds.refresh(Request())
34
+ else:
35
+ if not os.path.exists(CREDENTIALS_FILE):
36
+ raise FileNotFoundError(f"❌ {CREDENTIALS_FILE} not found.")
37
+ flow = InstalledAppFlow.from_client_secrets_file(CREDENTIALS_FILE, SCOPES)
38
+ creds = flow.run_local_server(port=0)
39
+ with open(TOKEN_FILE, 'wb') as token:
40
+ pickle.dump(creds, token)
41
+ return build('gmail', 'v1', credentials=creds)
42
+
43
+
44
+ # ---------- OpenRouter API ----------
45
+ def call_openrouter(prompt: str, model: str = "google/gemma-3-27b-it:free", max_tokens: int = 600):
46
+ if not OPENROUTER_API_KEY:
47
+ raise RuntimeError("❌ Set OPENROUTER_API_KEY in your .env file.")
48
+ headers = {"Authorization": f"Bearer {OPENROUTER_API_KEY}", "Content-Type": "application/json"}
49
+ payload = {
50
+ "model": model,
51
+ "messages": [
52
+ {"role": "system", "content": "You are a professional corporate email generator. Always produce clean, direct, and professional outputs."},
53
+ {"role": "user", "content": prompt},
54
+ ],
55
+ "max_tokens": max_tokens,
56
+ }
57
+ try:
58
+ r = requests.post(OPENROUTER_URL, json=payload, headers=headers, timeout=60)
59
+ r.raise_for_status()
60
+ return r.json()["choices"][0]["message"]["content"].strip()
61
+ except Exception as e:
62
+ return f"⚠️ Error contacting OpenRouter: {e}"
63
+
64
+
65
+ # ---------- Build & Send Email ----------
66
+ def build_and_send_email(recipient_email, recipient_name, subject, body, sender_name, sender_position, sender_contact, attachments=None):
67
+ if not recipient_email:
68
+ return "❌ Recipient email is required!"
69
+
70
+ try:
71
+ service = authenticate_gmail()
72
+
73
+ def clean_header(value: str) -> str:
74
+ return (value or "").replace("\r", "").replace("\n", "").strip()
75
+
76
+ recipient_email = clean_header(recipient_email)
77
+ subject = clean_header(subject)
78
+ sender_name = clean_header(sender_name)
79
+ sender_position = clean_header(sender_position)
80
+ sender_contact = clean_header(sender_contact)
81
+ recipient_name = clean_header(recipient_name)
82
+
83
+ signature = f"\n\nBest regards,\n{sender_name}\n{sender_position}\n{sender_contact}"
84
+ final_body = f"Dear {recipient_name or 'Sir/Madam'},\n\n{body.strip()}\n{signature}"
85
+
86
+ msg = EmailMessage()
87
+ msg["To"] = recipient_email
88
+ msg["Subject"] = subject or "(No Subject)"
89
+ msg["From"] = clean_header(f"{sender_name} <me@gmail.com>")
90
+ msg.set_content(final_body)
91
+
92
+ if attachments:
93
+ for file_obj in attachments:
94
+ file_path = Path(file_obj.name)
95
+ mime_type, _ = mimetypes.guess_type(file_path.name)
96
+ maintype, subtype = (mime_type or "application/octet-stream").split("/", 1)
97
+ with open(file_obj.name, "rb") as f:
98
+ msg.add_attachment(f.read(), maintype=maintype, subtype=subtype, filename=file_path.name)
99
+
100
+ raw_message = base64.urlsafe_b64encode(msg.as_bytes()).decode('utf-8')
101
+ service.users().messages().send(userId="me", body={'raw': raw_message}).execute()
102
+
103
+ return f"✅ Email sent successfully to {recipient_email}"
104
+
105
+ except Exception as e:
106
+ return f"❌ Failed to send email: {e}"
107
+
108
+
109
+ # ---------- AI Email Generator ----------
110
+ def generate_email(prompt_instructions, recipient_name, sender_name):
111
+ if not prompt_instructions:
112
+ return "Please enter email details.", ""
113
+
114
+ subject_prompt = (
115
+ f"Generate a short, professional email subject (max 8 words) "
116
+ f"for this topic: '{prompt_instructions}'. Output only the subject line."
117
+ )
118
+ subject = call_openrouter(subject_prompt, max_tokens=40)
119
+
120
+ body_prompt = (
121
+ f"Write a clear, concise, and professional email for this topic: '{prompt_instructions}'. "
122
+ f"Recipient: {recipient_name or 'Sir/Madam'}. Sender: {sender_name}. "
123
+ f"Start with 'Dear {recipient_name or 'Sir/Madam'},' and end with 'Best regards, {sender_name}'. "
124
+ f"Do not include markdown or numbered lists."
125
+ )
126
+ body = call_openrouter(body_prompt, max_tokens=600)
127
+ return subject.strip(), body.strip()
128
+
129
+
130
+ # ---------- Hugging Face Safe CSS ----------
131
+ custom_css = """
132
+ :root {
133
+ --primary-color: #58a6ff;
134
+ --background-color: #0d1117;
135
+ --secondary-bg: #161b22;
136
+ --text-color: #e6edf3;
137
+ }
138
+
139
+ html, body, .gradio-container {
140
+ background-color: var(--background-color) !important;
141
+ color: var(--text-color) !important;
142
+ font-family: 'Poppins', sans-serif !important;
143
+ }
144
+
145
+ .gr-block, .gr-panel, .gr-row, .gr-column {
146
+ background-color: var(--background-color) !important;
147
+ }
148
+
149
+ button, .gr-button {
150
+ background-color: var(--primary-color) !important;
151
+ color: white !important;
152
+ border-radius: 10px !important;
153
+ font-weight: 600 !important;
154
+ transition: 0.3s;
155
+ border: none !important;
156
+ }
157
+
158
+ button:hover, .gr-button:hover {
159
+ background-color: #1158c7 !important;
160
+ transform: scale(1.03);
161
+ }
162
+
163
+ textarea, input, .gr-textbox, .gr-text-input {
164
+ background-color: var(--secondary-bg) !important;
165
+ border: 1px solid #30363d !important;
166
+ color: var(--text-color) !important;
167
+ }
168
+
169
+ label, .gr-form-label {
170
+ color: var(--text-color) !important;
171
+ }
172
+
173
+ #main-title {
174
+ text-align: center;
175
+ font-size: 2.4em;
176
+ font-weight: 800;
177
+ color: var(--primary-color);
178
+ margin-top: 20px;
179
+ text-shadow: 0 0 12px rgba(88,166,255,0.5);
180
+ }
181
+
182
+ #subtext {
183
+ text-align: center;
184
+ font-size: 1.1em;
185
+ color: #c9d1d9;
186
+ opacity: 0.85;
187
+ margin-bottom: 25px;
188
+ }
189
+
190
+ #footer {
191
+ text-align: center;
192
+ font-size: 0.95em;
193
+ color: #8b949e;
194
+ margin-top: 40px;
195
+ padding: 10px;
196
+ border-top: 1px solid #30363d;
197
+ }
198
+ #footer span {
199
+ color: var(--primary-color);
200
+ font-weight: 600;
201
+ }
202
+ """
203
+
204
+ # ---------- Gradio Interface ----------
205
+ with gr.Blocks(css=custom_css, theme=gr.themes.Soft(), title="AI Email Generator & Sender") as demo:
206
+ gr.Markdown("<div id='main-title'>💌 AI Email Generator & Sender</div>")
207
+ gr.Markdown("<div id='subtext'>Generate and send polished, professional emails instantly via Gmail API 🚀</div>")
208
+
209
+ with gr.Column(scale=1):
210
+ with gr.Row():
211
+ recipient_email = gr.Textbox(label="Recipient Email", placeholder="example@domain.com")
212
+ recipient_name = gr.Textbox(label="Recipient Name", placeholder="Mr./Ms. Name")
213
+
214
+ prompt_instructions = gr.Textbox(
215
+ label="Email Purpose / Instructions",
216
+ lines=4,
217
+ placeholder="e.g., Send project update with attached report"
218
+ )
219
+
220
+ with gr.Row():
221
+ sender_name = gr.Textbox(label="Your Name", value="Selvaganesh V")
222
+ sender_position = gr.Textbox(label="Your Position", value="AI Engineer")
223
+ sender_contact = gr.Textbox(label="Your Contact Info", value="selvavelayutham395@gmail.com")
224
+
225
+ generate_btn = gr.Button("🤖 Generate Subject & Body")
226
+ subject_box = gr.Textbox(label="Subject", lines=1)
227
+ body_box = gr.Textbox(label="Body", lines=10)
228
+ attachment = gr.File(label="Add Attachments (optional)", file_count="multiple", type="filepath")
229
+ send_btn = gr.Button("📨 Send Email")
230
+ status_box = gr.Textbox(label="Status", lines=3)
231
+
232
+ generate_btn.click(generate_email,
233
+ inputs=[prompt_instructions, recipient_name, sender_name],
234
+ outputs=[subject_box, body_box])
235
+
236
+ send_btn.click(build_and_send_email,
237
+ inputs=[recipient_email, recipient_name, subject_box, body_box,
238
+ sender_name, sender_position, sender_contact, attachment],
239
+ outputs=[status_box])
240
+
241
+ gr.Markdown("<div id='footer'>Made with ❤️ by <span>Selvaganesh V</span></div>")
242
+
243
+ if __name__ == "__main__":
244
+ demo.launch(server_name="0.0.0.0", server_port=7860, share=True,debug=True)
requirements.txt ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
 
1
+ gradio
2
+ requests
3
+ python-dotenv
4
+ google-auth
5
+ google-auth-oauthlib
6
+ google-auth-httplib2
7
+ google-api-python-client
8
+ pathlib
token.pickle ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:538f7dd3959f15de08030ebb91eb97bf30eea267a01d65c35b0db017b19dcc0c
3
+ size 1031