fix: perms
perso/mcp-maildir/pipeline/head This commit looks good

This commit is contained in:
Julien Cabillot
2026-02-27 10:32:42 -05:00
parent b96277064a
commit 4e45f3e8d9
6 changed files with 388 additions and 22 deletions
+24 -10
View File
@@ -6,7 +6,7 @@ import os
import email
import mailbox
from datetime import datetime
from email.utils import parsedate_to_datetime
from email.utils import parsedate_to_datetime, parseaddr
from email.header import decode_header
from typing import List, Dict, Any, Tuple
import uuid
@@ -14,7 +14,7 @@ import uuid
from dotenv import load_dotenv
from qdrant_client import QdrantClient
from qdrant_client.http import models
from sentence_transformers import SentenceTransformer
from fastembed import TextEmbedding
from bs4 import BeautifulSoup
# Load .env config
@@ -32,7 +32,7 @@ if not QDRANT_URL:
if not COLLECTION_NAME:
raise ValueError("COLLECTION_NAME environment variable is required.")
EMBEDDING_MODEL_NAME = "all-MiniLM-L6-v2"
EMBEDDING_MODEL_NAME = os.environ.get("EMBEDDING_MODEL_NAME", "BAAI/bge-small-en-v1.5")
BATCH_SIZE = 50
def decode_mime_words(s: str) -> str:
@@ -59,6 +59,14 @@ def extract_text_from_html(html_content: str) -> str:
except Exception:
return html_content
def normalize_email_address(value: str) -> str:
"""Extracts and normalizes the bare email address from a header value."""
if not value:
return ""
_, addr = parseaddr(value)
return (addr or value).strip().lower()
def parse_email_message(msg: mailbox.Message) -> Tuple[str, List[str]]:
"""Extracts plain text body and a list of attachment filenames."""
body_parts = []
@@ -99,9 +107,8 @@ def parse_email_message(msg: mailbox.Message) -> Tuple[str, List[str]]:
return "\n".join(body_parts).strip(), attachments
def init_qdrant_collection(client: QdrantClient, model: SentenceTransformer):
def init_qdrant_collection(client: QdrantClient, vector_size: int):
"""Ensures Qdrant collection exists and payload indexes are created."""
vector_size = model.get_sentence_embedding_dimension()
# Check if collection exists
collections = client.get_collections().collections
@@ -151,12 +158,13 @@ def main():
# Initialize model
print(f"Loading embedding model: {EMBEDDING_MODEL_NAME}...")
model = SentenceTransformer(EMBEDDING_MODEL_NAME)
model = TextEmbedding(model_name=EMBEDDING_MODEL_NAME)
vector_size = len(next(iter(model.embed(["dimension_probe"])) ))
# Initialize Qdrant
print("Connecting to Qdrant...")
qdrant_client = QdrantClient(url=QDRANT_URL)
init_qdrant_collection(qdrant_client, model)
init_qdrant_collection(qdrant_client, vector_size)
points = []
@@ -173,8 +181,10 @@ def main():
try:
# Parse headers
subject = decode_mime_words(msg.get("Subject", "No Subject"))
sender = decode_mime_words(msg.get("From", "Unknown"))
receiver = decode_mime_words(msg.get("To", "Unknown"))
sender_raw = decode_mime_words(msg.get("From", "Unknown"))
receiver_raw = decode_mime_words(msg.get("To", "Unknown"))
sender = normalize_email_address(sender_raw)
receiver = normalize_email_address(receiver_raw)
message_id = msg.get("Message-ID", str(uuid.uuid4()))
# Parse date
@@ -207,14 +217,18 @@ def main():
)
# Embed the text
vector = model.encode(vector_text).tolist()
# Fastembed returns an iterable of numpy arrays
embeddings = list(model.embed([vector_text]))
vector = embeddings[0].tolist()
# Prepare payload (metadata)
payload = {
"message_id": message_id,
"date": iso_date,
"sender": sender,
"sender_raw": sender_raw,
"receiver": receiver,
"receiver_raw": receiver_raw,
"subject": subject,
"body_text": body_text,
"attachments": attachments