Marylene commited on
Commit
8504a87
·
1 Parent(s): 51b602a

Try to send an email

Browse files
Files changed (3) hide show
  1. agent.py +1 -1
  2. app.py +25 -11
  3. email_sender.py +28 -43
agent.py CHANGED
@@ -15,7 +15,7 @@ def generate_email(client, to_email: str, context: str, tone: str) -> tuple[str,
15
  Contexte : {context}
16
  Ton : {tone}
17
 
18
- Réponds en deux parties :
19
  1. Objet : ligne d'objet de l'email
20
  2. Corps : contenu de l'email bien rédigé, en respectant le ton demandé.
21
  Commence chaque partie par son étiquette.
 
15
  Contexte : {context}
16
  Ton : {tone}
17
 
18
+ Réponds de manière courte en deux parties :
19
  1. Objet : ligne d'objet de l'email
20
  2. Corps : contenu de l'email bien rédigé, en respectant le ton demandé.
21
  Commence chaque partie par son étiquette.
app.py CHANGED
@@ -8,17 +8,31 @@ def on_generate(to_email, context, tone):
8
  subject, body = generate_email(model, to_email, context, tone)
9
  return subject, body
10
 
11
- def on_send(sender_email, to_email, subject, body):
12
- success, message = send_email(sender_email, to_email, subject, body)
13
  return message
14
 
15
- with gr.Blocks(title="Assistant Email Pro - HuggingFace LLM") as demo:
16
- gr.Markdown("# ✉️ Assistant Email avec génération automatique")
17
-
18
- sender = gr.Textbox(label="Expéditeur (adresse Gmail utilisée)")
19
- to_email = gr.Textbox(label="Destinataire", placeholder="exemple@exemple.com")
20
- context = gr.Textbox(label="Contexte ou objectif", lines=4,
21
- placeholder="Demander un rendez-vous, féliciter un collègue...")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
22
  tone = gr.Dropdown(choices=["Formel", "Chaleureux", "Direct", "Poli"],
23
  value="Formel", label="Ton")
24
 
@@ -32,6 +46,6 @@ with gr.Blocks(title="Assistant Email Pro - HuggingFace LLM") as demo:
32
  status = gr.Markdown()
33
 
34
  generate_btn.click(on_generate, inputs=[to_email, context, tone], outputs=[subject, body])
35
- send_btn.click(on_send, inputs=[sender, to_email, subject, body], outputs=status)
36
 
37
- demo.launch()
 
8
  subject, body = generate_email(model, to_email, context, tone)
9
  return subject, body
10
 
11
+ def on_send(refresh_token, from_email, to_email, subject, body):
12
+ success, message = send_email(refresh_token, to_email, subject, body, from_email)
13
  return message
14
 
15
+ with gr.Blocks(title="Assistant Email - Gmail sécurisé", theme="soft") as demo:
16
+ gr.Markdown("# ✉️ Générateur d’e-mails avec envoi Gmail sécurisé")
17
+
18
+ with gr.Accordion("🔐 Connexion Gmail - instructions", open=False):
19
+ gr.Markdown("""
20
+ ### Étapes pour générer votre token Gmail :
21
+
22
+ 1. Ouvrez [Google OAuth Playground](https://developers.google.com/oauthplayground)
23
+ 2. Cliquez sur ⚙️ (roue dentée) en haut à droite → cochez **Use your own OAuth credentials**
24
+ - `client_id` : fourni par le Space (dans Hugging Face Secrets)
25
+ - `client_secret` : fourni également
26
+ 3. Choisissez ce scope :
27
+ https://www.googleapis.com/auth/gmail.send
28
+ 4. Cliquez sur **Authorize APIs** → puis sur **Exchange authorization code for tokens**
29
+ 5. Copiez-collez ici le `refresh_token`
30
+ """)
31
+
32
+ refresh_token = gr.Textbox(label="🔑 Refresh Token Gmail (copié depuis OAuth Playground)", type="password")
33
+ from_email = gr.Textbox(label="Adresse Gmail utilisée (expéditeur)")
34
+ to_email = gr.Textbox(label="Destinataire", placeholder="exemple@insee.fr")
35
+ context = gr.Textbox(label="Contexte ou objectif", lines=3)
36
  tone = gr.Dropdown(choices=["Formel", "Chaleureux", "Direct", "Poli"],
37
  value="Formel", label="Ton")
38
 
 
46
  status = gr.Markdown()
47
 
48
  generate_btn.click(on_generate, inputs=[to_email, context, tone], outputs=[subject, body])
49
+ send_btn.click(on_send, inputs=[refresh_token, from_email, to_email, subject, body], outputs=status)
50
 
51
+ demo.launch()
email_sender.py CHANGED
@@ -1,56 +1,41 @@
1
  import os
2
  import base64
3
- import pickle
4
  from email.mime.text import MIMEText
5
- from google_auth_oauthlib.flow import InstalledAppFlow
6
  from google.auth.transport.requests import Request
 
7
  from googleapiclient.discovery import build
8
 
9
- SCOPES = ["https://www.googleapis.com/auth/gmail.send"]
10
- CREDENTIALS_PATH = "client_secret.json"
11
-
12
- # Stocker les tokens par email utilisateur
13
- def get_token_path(sender_email):
14
- safe_email = sender_email.replace("@", "_at_").replace(".", "_dot_")
15
- return f"token_{safe_email}.pkl"
16
-
17
- # Écrire le client secret s'il est fourni par variable d'env
18
- client_secret_content = os.getenv("CLIENT_SECRET_JSON")
19
- if client_secret_content and not os.path.exists(CREDENTIALS_PATH):
20
- with open(CREDENTIALS_PATH, "w") as f:
21
- f.write(client_secret_content)
22
-
23
- def authenticate_gmail(sender_email: str):
24
- creds = None
25
- token_path = get_token_path(sender_email)
26
-
27
- if os.path.exists(token_path):
28
- with open(token_path, "rb") as token:
29
- creds = pickle.load(token)
30
-
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
- flow = InstalledAppFlow.from_client_secrets_file(CREDENTIALS_PATH, SCOPES)
36
- creds = flow.run_local_server(port=0)
37
- with open(token_path, "wb") as token:
38
- pickle.dump(creds, token)
39
-
40
  return build("gmail", "v1", credentials=creds)
41
 
42
- def send_email(sender_email: str, to_email: str, subject: str, body: str):
43
- service = authenticate_gmail(sender_email)
 
 
 
 
 
 
44
 
45
- message = MIMEText(body)
46
- message["to"] = to_email
47
- message["subject"] = subject
48
- message["from"] = sender_email
49
- raw_message = base64.urlsafe_b64encode(message.as_bytes()).decode()
50
- send_message = {"raw": raw_message}
51
 
52
- try:
53
  sent = service.users().messages().send(userId="me", body=send_message).execute()
54
- return True, f"✅ Email envoyé à {to_email} (ID: {sent['id']})"
55
  except Exception as e:
56
  return False, f"❌ Échec de l'envoi : {e}"
 
1
  import os
2
  import base64
 
3
  from email.mime.text import MIMEText
 
4
  from google.auth.transport.requests import Request
5
+ from google.oauth2.credentials import Credentials
6
  from googleapiclient.discovery import build
7
 
8
+ def authenticate_gmail_with_refresh_token(refresh_token: str):
9
+ client_id = os.getenv("GMAIL_CLIENT_ID")
10
+ client_secret = os.getenv("GMAIL_CLIENT_SECRET")
11
+
12
+ if not client_id or not client_secret:
13
+ raise ValueError("Client ID ou Client Secret manquant (définir dans les secrets Hugging Face)")
14
+
15
+ creds = Credentials(
16
+ None,
17
+ refresh_token=refresh_token,
18
+ token_uri="https://oauth2.googleapis.com/token",
19
+ client_id=client_id,
20
+ client_secret=client_secret,
21
+ scopes=["https://www.googleapis.com/auth/gmail.send"]
22
+ )
23
+ creds.refresh(Request())
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
24
  return build("gmail", "v1", credentials=creds)
25
 
26
+ def send_email(refresh_token: str, to_email: str, subject: str, body: str, from_email: str):
27
+ try:
28
+ service = authenticate_gmail_with_refresh_token(refresh_token)
29
+
30
+ message = MIMEText(body)
31
+ message["to"] = to_email
32
+ message["subject"] = subject
33
+ message["from"] = from_email
34
 
35
+ raw_message = base64.urlsafe_b64encode(message.as_bytes()).decode()
36
+ send_message = {"raw": raw_message}
 
 
 
 
37
 
 
38
  sent = service.users().messages().send(userId="me", body=send_message).execute()
39
+ return True, f"✅ Email envoyé à {to_email} (ID : {sent['id']})"
40
  except Exception as e:
41
  return False, f"❌ Échec de l'envoi : {e}"