Spaces:
Sleeping
Sleeping
FIX
Browse files- agent.py +25 -32
- app.py +19 -20
- email_sender.py +24 -18
agent.py
CHANGED
|
@@ -1,22 +1,14 @@
|
|
| 1 |
-
import os
|
| 2 |
from huggingface_hub import InferenceClient
|
|
|
|
| 3 |
|
| 4 |
-
|
| 5 |
-
|
| 6 |
-
Génère un email en deux parties : sujet et corps du message.
|
| 7 |
-
|
| 8 |
-
Args:
|
| 9 |
-
model_id (str): ID du modèle HF.
|
| 10 |
-
to (str): Adresse email cible.
|
| 11 |
-
context (str): Contexte du message.
|
| 12 |
-
tone (str): Ton souhaité (formel, amical, chaleureux...).
|
| 13 |
|
| 14 |
-
|
| 15 |
-
|
| 16 |
-
"""
|
| 17 |
-
client = InferenceClient(model=model_id, token=os.getenv("HF_TOKEN"))
|
| 18 |
|
| 19 |
-
prompt = f"""
|
|
|
|
| 20 |
|
| 21 |
Contexte : {context}
|
| 22 |
Ton : {tone}
|
|
@@ -25,21 +17,22 @@ Réponds en deux parties :
|
|
| 25 |
1. Objet : ligne d'objet de l'email
|
| 26 |
2. Corps : contenu de l'email bien rédigé, en respectant le ton demandé.
|
| 27 |
Commence chaque partie par son étiquette.
|
| 28 |
-
"""
|
| 29 |
-
|
| 30 |
-
|
| 31 |
-
|
| 32 |
-
|
| 33 |
-
|
| 34 |
-
|
| 35 |
-
|
| 36 |
-
|
| 37 |
-
|
| 38 |
-
|
| 39 |
-
|
| 40 |
-
|
| 41 |
-
|
| 42 |
-
|
| 43 |
-
|
| 44 |
-
|
|
|
|
| 45 |
return subject, body
|
|
|
|
|
|
|
| 1 |
from huggingface_hub import InferenceClient
|
| 2 |
+
import os
|
| 3 |
|
| 4 |
+
# Utilise le token depuis les secrets HF
|
| 5 |
+
HF_TOKEN = os.getenv("HUGGINGFACEHUB_API_TOKEN")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 6 |
|
| 7 |
+
def generate_email(model_id, to_email, context, tone):
|
| 8 |
+
client = InferenceClient(token=HF_TOKEN)
|
|
|
|
|
|
|
| 9 |
|
| 10 |
+
prompt = f"""
|
| 11 |
+
Tu es un assistant virtuel. Rédige un email destiné à {to_email}.
|
| 12 |
|
| 13 |
Contexte : {context}
|
| 14 |
Ton : {tone}
|
|
|
|
| 17 |
1. Objet : ligne d'objet de l'email
|
| 18 |
2. Corps : contenu de l'email bien rédigé, en respectant le ton demandé.
|
| 19 |
Commence chaque partie par son étiquette.
|
| 20 |
+
""".strip()
|
| 21 |
+
|
| 22 |
+
try:
|
| 23 |
+
response = client.text_generation(
|
| 24 |
+
model=model_id,
|
| 25 |
+
prompt=prompt,
|
| 26 |
+
max_new_tokens=512,
|
| 27 |
+
temperature=0.7,
|
| 28 |
+
)
|
| 29 |
+
return parse_email(response)
|
| 30 |
+
except Exception as e:
|
| 31 |
+
return "Erreur", f"❌ Erreur de génération : {e}"
|
| 32 |
+
|
| 33 |
+
def parse_email(text):
|
| 34 |
+
lines = text.strip().split("\n")
|
| 35 |
+
subject = next((line for line in lines if line.lower().startswith("objet")), "Objet : (non trouvé)")
|
| 36 |
+
body_lines = [line for line in lines if not line.lower().startswith("objet")]
|
| 37 |
+
body = "\n".join(body_lines).strip()
|
| 38 |
return subject, body
|
app.py
CHANGED
|
@@ -6,31 +6,30 @@ def on_generate(to_email, context, tone):
|
|
| 6 |
subject, body = generate_email("mistralai/Mistral-7B-Instruct-v0.1", to_email, context, tone)
|
| 7 |
return subject, body
|
| 8 |
|
| 9 |
-
def on_send(to_email, subject, body,
|
| 10 |
-
|
| 11 |
-
return msg
|
| 12 |
|
| 13 |
-
with gr.Blocks(theme=
|
| 14 |
-
gr.Markdown("## ✉️
|
| 15 |
|
| 16 |
with gr.Row():
|
| 17 |
-
|
| 18 |
-
|
| 19 |
-
|
|
|
|
|
|
|
| 20 |
|
| 21 |
-
|
| 22 |
-
|
|
|
|
| 23 |
|
| 24 |
with gr.Row():
|
| 25 |
-
|
| 26 |
-
|
|
|
|
|
|
|
| 27 |
|
| 28 |
-
|
| 29 |
-
|
| 30 |
|
| 31 |
-
|
| 32 |
-
|
| 33 |
-
generate_btn.click(fn=on_generate, inputs=[to_email, context, tone], outputs=[subject, body])
|
| 34 |
-
send_btn.click(fn=on_send, inputs=[to_email, subject, body, sender_email, refresh_token], outputs=status)
|
| 35 |
-
|
| 36 |
-
demo.launch()
|
|
|
|
| 6 |
subject, body = generate_email("mistralai/Mistral-7B-Instruct-v0.1", to_email, context, tone)
|
| 7 |
return subject, body
|
| 8 |
|
| 9 |
+
def on_send(sender_email, to_email, subject, body, refresh_token):
|
| 10 |
+
return send_email(sender_email, to_email, subject, body, refresh_token)
|
|
|
|
| 11 |
|
| 12 |
+
with gr.Blocks(theme=gr.themes.Base(), css="body { background-color: #111; color: white; }") as app:
|
| 13 |
+
gr.Markdown("## ✉️ Agent d'envoi de mails", elem_id="title")
|
| 14 |
|
| 15 |
with gr.Row():
|
| 16 |
+
with gr.Column():
|
| 17 |
+
to_email = gr.Text(label="Destinataire")
|
| 18 |
+
context = gr.Text(label="Contexte de l'email")
|
| 19 |
+
tone = gr.Dropdown(["Chaleureux", "Formel", "Amical"], value="Chaleureux", label="Ton")
|
| 20 |
+
generate_btn = gr.Button("✏️ Générer l'email")
|
| 21 |
|
| 22 |
+
with gr.Column():
|
| 23 |
+
subject_output = gr.Text(label="Objet")
|
| 24 |
+
body_output = gr.TextArea(label="Corps de l'email", lines=15)
|
| 25 |
|
| 26 |
with gr.Row():
|
| 27 |
+
sender_email = gr.Text(label="Adresse d'envoi (Gmail)")
|
| 28 |
+
refresh_token = gr.Text(label="Refresh Token Gmail", type="password")
|
| 29 |
+
send_btn = gr.Button("📤 Envoyer le mail")
|
| 30 |
+
status = gr.Textbox(label="Statut")
|
| 31 |
|
| 32 |
+
generate_btn.click(on_generate, inputs=[to_email, context, tone], outputs=[subject_output, body_output])
|
| 33 |
+
send_btn.click(on_send, inputs=[sender_email, to_email, subject_output, body_output, refresh_token], outputs=status)
|
| 34 |
|
| 35 |
+
app.launch()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
email_sender.py
CHANGED
|
@@ -1,31 +1,37 @@
|
|
| 1 |
-
import os
|
| 2 |
import base64
|
|
|
|
| 3 |
from email.mime.text import MIMEText
|
|
|
|
| 4 |
from google.oauth2.credentials import Credentials
|
| 5 |
from googleapiclient.discovery import build
|
| 6 |
|
| 7 |
-
#
|
| 8 |
-
|
| 9 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 10 |
|
| 11 |
-
|
| 12 |
-
if not
|
| 13 |
-
|
| 14 |
|
| 15 |
-
|
| 16 |
-
|
| 17 |
-
refresh_token=refresh_token,
|
| 18 |
-
token_uri="https://oauth2.googleapis.com/token",
|
| 19 |
-
client_id=GMAIL_CLIENT_ID,
|
| 20 |
-
client_secret=GMAIL_CLIENT_SECRET,
|
| 21 |
-
scopes=["https://www.googleapis.com/auth/gmail.send"]
|
| 22 |
-
)
|
| 23 |
|
|
|
|
| 24 |
try:
|
| 25 |
-
service =
|
| 26 |
message = MIMEText(body)
|
| 27 |
message["to"] = to_email
|
| 28 |
-
message["from"] =
|
| 29 |
message["subject"] = subject
|
| 30 |
|
| 31 |
raw_message = base64.urlsafe_b64encode(message.as_bytes()).decode()
|
|
@@ -34,4 +40,4 @@ def send_email(from_email, to_email, subject, body, refresh_token):
|
|
| 34 |
sent = service.users().messages().send(userId="me", body=send_body).execute()
|
| 35 |
return True, f"✅ Email envoyé à {to_email} (ID: {sent['id']})"
|
| 36 |
except Exception as e:
|
| 37 |
-
return False, f"❌ Erreur
|
|
|
|
|
|
|
| 1 |
import base64
|
| 2 |
+
import os
|
| 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 |
+
# Client ID / secret à stocker dans les secrets HF (cf. variables d’environnement du Space)
|
| 9 |
+
CLIENT_ID = os.getenv("GMAIL_CLIENT_ID")
|
| 10 |
+
CLIENT_SECRET = os.getenv("GMAIL_CLIENT_SECRET")
|
| 11 |
+
|
| 12 |
+
def authenticate_gmail(sender_email, refresh_token):
|
| 13 |
+
creds_data = {
|
| 14 |
+
"token": "",
|
| 15 |
+
"refresh_token": refresh_token,
|
| 16 |
+
"token_uri": "https://oauth2.googleapis.com/token",
|
| 17 |
+
"client_id": CLIENT_ID,
|
| 18 |
+
"client_secret": CLIENT_SECRET,
|
| 19 |
+
"scopes": ["https://www.googleapis.com/auth/gmail.send"]
|
| 20 |
+
}
|
| 21 |
|
| 22 |
+
creds = Credentials.from_authorized_user_info(info=creds_data)
|
| 23 |
+
if not creds.valid and creds.expired and creds.refresh_token:
|
| 24 |
+
creds.refresh(Request())
|
| 25 |
|
| 26 |
+
service = build("gmail", "v1", credentials=creds)
|
| 27 |
+
return service
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 28 |
|
| 29 |
+
def send_email(sender_email, to_email, subject, body, refresh_token):
|
| 30 |
try:
|
| 31 |
+
service = authenticate_gmail(sender_email, refresh_token)
|
| 32 |
message = MIMEText(body)
|
| 33 |
message["to"] = to_email
|
| 34 |
+
message["from"] = sender_email
|
| 35 |
message["subject"] = subject
|
| 36 |
|
| 37 |
raw_message = base64.urlsafe_b64encode(message.as_bytes()).decode()
|
|
|
|
| 40 |
sent = service.users().messages().send(userId="me", body=send_body).execute()
|
| 41 |
return True, f"✅ Email envoyé à {to_email} (ID: {sent['id']})"
|
| 42 |
except Exception as e:
|
| 43 |
+
return False, f"❌ Erreur d'envoi : {e}"
|