add agent workspace

This commit is contained in:
2026-02-18 22:39:35 -08:00
commit e8389b8772
48 changed files with 3476 additions and 0 deletions

View File

@@ -0,0 +1,16 @@
{
"imap": {
"host": "imap.migadu.com",
"port": 993,
"email": "youlu@luyanxin.com",
"password": "kDkNau2r7m.hV!uk*D4Yr8mC7Dyjx9T"
},
"ollama": {
"host": "http://localhost:11434",
"model": "qwen3:4b"
},
"rules": {
"max_body_length": 1000,
"check_unseen_only": true
}
}

View File

@@ -0,0 +1,52 @@
{
"msg_f1d43ea3": {
"imap_uid": "2",
"subject": "Delivered: \"Voikinfo Bottom Gusset Bags...\"",
"sender": "\"Amazon.com - order-update(a)amazon.com\"\r\n <order-update_at_amazon_com_posyo@simplelogin.co>",
"recipient": "sho.amazon@ylu17.com",
"summary": "Your Amazon package (order #114-1496788-7649829) was delivered today to Argo, Los Angeles, CA and left near the front door or porch.",
"email_date": "Wed, 18 Feb 2026 04:15:24 +0000",
"status": "pending",
"found_at": "2026-02-18T16:18:42.347538"
},
"msg_60c56a87": {
"imap_uid": "3",
"subject": "=?UTF-8?b?5L2V5LiN5ruh6Laz6Ieq5bex55qE5Y+j6IW55LmL5qyy?=",
"sender": "\"Uber Eats - uber(a)uber.com\" <uber_at_uber_com_kjwzyhxn@simplelogin.co>",
"recipient": "uber@ylu17.com",
"summary": "Uber Eats has sent a notification that the user's order is ready for pickup.",
"email_date": "Wed, 18 Feb 2026 11:36:59 +0000",
"status": "pending",
"found_at": "2026-02-18T08:05:56.594842"
},
"msg_ebd24205": {
"imap_uid": "4",
"subject": "Your order has been shipped (or closed if combined/delivered).",
"sender": "\"cd(a)woodenswords.com\"\r\n <cd_at_woodenswords_com_xivwijojc@simplelogin.co>",
"recipient": "mail@luyx.org",
"summary": "This email confirms that your order has been shipped or closed (if combined/delivered).",
"email_date": "Wed, 18 Feb 2026 16:07:58 +0000",
"status": "pending",
"found_at": "2026-02-18T12:01:19.048091"
},
"msg_fa73b3bd": {
"imap_uid": "6",
"subject": "=?UTF-8?Q?Yanxin,_I=E2=80=99m_still_waiting_for_your_response?=",
"sender": "\"Arslan (via LinkedIn) - messages-noreply(a)linkedin.com\"\r\n <messages-noreply_at_linkedin_com_ajpnalmwp@simplelogin.co>",
"recipient": "Yanxin Lu <acc.linkedin@ylu17.com>",
"summary": "Arslan Ahmed, a Senior AI | ML | Full Stack Engineer from Ilford, invited you to connect on February 11, 2026 at 10:08 PM and is waiting for your response.",
"email_date": "Wed, 18 Feb 2026 18:53:45 +0000 (UTC)",
"status": "pending",
"found_at": "2026-02-18T12:04:34.602407"
},
"msg_59f23736": {
"imap_uid": "1",
"subject": "New Software Engineer jobs that match your profile",
"sender": "\"LinkedIn - jobs-noreply(a)linkedin.com\"\r\n <jobs-noreply_at_linkedin_com_zuwggfxh@simplelogin.co>",
"recipient": "Yanxin Lu <acc.linkedin@ylu17.com>",
"summary": "LinkedIn has notified the user of new software engineering jobs that match their profile and includes a link to update their top card.",
"email_date": "Wed, 18 Feb 2026 02:07:12 +0000 (UTC)",
"status": "pending",
"found_at": "2026-02-18T16:16:00.784822"
}
}

View File

@@ -0,0 +1,50 @@
[2026-02-15 21:14:02] KEPT: Please confirm your mailbox youlu@luyanxin.com
From: "noreply@simplelogin.io" <noreply@simplelogin.io>
Analysis: KEEP: Legitimate service confirmation email for mailbox addition (not promotional)
[2026-02-15 21:15:04] KEPT: =?utf-8?B?RndkOiBHZXQgMTAlIG9mZiB5b3VyIG5leHQgb3JkZXIg4pyF?=
From: "Yanxin Lu - crac1017(a)hotmail.com"
<crac1017_at_hotmail_com_fndbbu@simplelogin.co>
Analysis: KEEP: error - HTTPConnectionPool(host='localhost', port=11434): Read timed out. (read timeout=60)
[2026-02-15 21:15:37] KEPT:
=?utf-8?B?RndkOiDigJxzb2Z0d2FyZSBlbmdpbmVlcuKAnTogTWljcm9
From: "Yanxin Lu - crac1017(a)hotmail.com"
<crac1017_at_hotmail_com_fndbbu@simplelogin.co>
Analysis: KEEP: LinkedIn job alert notification for subscribed job search (not promotional)
[2026-02-15 21:15:52] KEPT: Fwd: Your receipt from OpenRouter, Inc #2231-9732
From: "Yanxin Lu - crac1017(a)hotmail.com"
<crac1017_at_hotmail_com_fndbbu@simplelogin.co>
Analysis: KEEP: This is a legitimate receipt for a payment made to OpenRouter, Inc (a known AI service provider), not promotional content.
[2026-02-15 21:16:10] KEPT: Fwd: Your ChatGPT code is 217237
From: "Yanxin Lu - crac1017(a)hotmail.com"
<crac1017_at_hotmail_com_fndbbu@simplelogin.co>
Analysis: KEEP: Legitimate security verification code from OpenAI (standard login confirmation)
[2026-02-15 22:49:44] KEPT (69.0s): =?UTF-8?B?5rWL6K+V6YKu5Lu2?=
From: Yanxin Lu <lyx@luyanxin.com>
Analysis: KEEP: Test email for delivery verification
From: Yanxin Lu <lyx@luyanxin.com>
Analysis: KEEP: Test email for delivery verification
[2026-02-15 22:57:03] MOVED_TO_TRASH (68.5s): =?utf-8?B?RndkOiBHZXQgMTAlIG9mZiB5b3VyIG5leHQgb3JkZXIg4pyF?=
From: "Yanxin Lu - crac1017(a)hotmail.com"
<crac1017_at_hotmail_com_fndbbu@simplelogin.co>
Analysis: AD: Forwarded Uber promotional offer
From: "Yanxin Lu - crac1017(a)hotmail.com"
<crac1017_at_hotmail_com_fndbbu@simplelogin.co>
Analysis: AD: Forwarded Uber promotional offer
[2026-02-15 23:00:09] KEPT (120.1s): Fwd: Your ChatGPT code is 217237
From: "Yanxin Lu - crac1017(a)hotmail.com"
<crac1017_at_hotmail_com_fndbbu@simplelogin.co>
Analysis: KEEP: error - HTTPConnectionPool(host='localhost', port=11434): Read timed out. (read timeout=120)
From: "Yanxin Lu - crac1017(a)hotmail.com"
<crac1017_at_hotmail_com_fndbbu@simplelogin.co>
Analysis: KEEP: error - HTTPConnectionPool(host='localhost', port=11434): Read timed out. (read timeout=120)

View File

@@ -0,0 +1,29 @@
[2026-02-18 08:04:26] ADDED_TO_PENDING (msg_f1d43ea3) (108.6s): Delivered: "Voikinfo Bottom Gusset Bags..."
From: "Amazon.com - order-update(a)amazon.com"
<order-update_at_amazon_com_posyo@simplelogin.co>
Analysis: KEEP: Standard delivery confirmation from Amazon
[2026-02-18 08:05:56] ADDED_TO_PENDING (msg_60c56a87) (88.0s): =?UTF-8?b?5L2V5LiN5ruh6Laz6Ieq5bex55qE5Y+j6IW55LmL5qyy?=
From: "Uber Eats - uber(a)uber.com" <uber_at_uber_com_kjwzyhxn@simplelogin.co>
Analysis: KEEP: The decoded subject line "Your Uber Eats order is ready!" indicates a transactional order update, not an advertisement.
[2026-02-18 12:01:19] ADDED_TO_PENDING (msg_ebd24205) (66.7s): Your order has been shipped (or closed if combined/delivered
From: "cd(a)woodenswords.com"
<cd_at_woodenswords_com_xivwijojc@simplelogin.co>
Analysis: KEEP: System-generated shipping update notification from an e-commerce store, not promotional content.
[2026-02-18 12:03:36] MOVED_TO_TRASH (133.4s): =?UTF-8?Q?=E2=80=9Csoftware_engineer=E2=80=9D:_Snap_Inc._-_S
From: "LinkedIn Job Alerts - jobalerts-noreply(a)linkedin.com"
<jobalerts-noreply_at_linkedin_com_cnrlhok@simplelogin.co>
Analysis: AD: This email is a promotional job alert notification from LinkedIn's service for users who have set up job preferences.
[2026-02-18 12:04:34] ADDED_TO_PENDING (msg_fa73b3bd) (57.3s): =?UTF-8?Q?Yanxin,_I=E2=80=99m_still_waiting_for_your_respons
From: "Arslan (via LinkedIn) - messages-noreply(a)linkedin.com"
<messages-noreply_at_linkedin_com_ajpnalmwp@simplelogin.co>
Analysis: KEEP: This is a standard LinkedIn connection request notification with no promotional content, discounts, or advertisements—only a reminder of an existing invitation.
[2026-02-18 16:18:42] ADDED_TO_PENDING (msg_f1d43ea3) (102.1s): Delivered: "Voikinfo Bottom Gusset Bags..."
From: "Amazon.com - order-update(a)amazon.com"
<order-update_at_amazon_com_posyo@simplelogin.co>
Analysis: KEEP: Standard delivery confirmation from Amazon, not a promotional message.

View File

@@ -0,0 +1,295 @@
#!/usr/bin/env python3
"""
Email Processor - Auto filter ads using local Qwen3
Moves ad emails to Trash folder (not permanently deleted)
"""
import json
import imaplib
import email
import os
import sys
from datetime import datetime
from pathlib import Path
# Config
SCRIPT_DIR = Path(__file__).parent
CONFIG_FILE = SCRIPT_DIR / "config.json"
LOGS_DIR = SCRIPT_DIR / "logs"
DATA_DIR = SCRIPT_DIR / "data"
PENDING_FILE = DATA_DIR / "pending_emails.json"
def load_config():
"""Load configuration"""
with open(CONFIG_FILE) as f:
return json.load(f)
def connect_imap(config):
"""Connect to IMAP server"""
imap_config = config['imap']
mail = imaplib.IMAP4_SSL(imap_config['host'], imap_config['port'])
mail.login(imap_config['email'], imap_config['password'])
return mail
def get_unseen_emails(mail):
"""Get list of unseen email IDs"""
mail.select('INBOX')
_, search_data = mail.search(None, 'UNSEEN')
email_ids = search_data[0].split()
return email_ids
def fetch_email(mail, email_id):
"""Fetch email content"""
_, msg_data = mail.fetch(email_id, '(RFC822)')
raw_email = msg_data[0][1]
msg = email.message_from_bytes(raw_email)
# Extract subject
subject = msg['Subject'] or '(No Subject)'
# Extract sender
sender = msg['From'] or '(Unknown)'
# Extract recipient
recipient = msg['To'] or '(Unknown)'
# Extract date
date = msg['Date'] or datetime.now().isoformat()
# Extract body
body = ""
if msg.is_multipart():
for part in msg.walk():
if part.get_content_type() == "text/plain":
try:
body = part.get_payload(decode=True).decode('utf-8', errors='ignore')
break
except:
pass
else:
try:
body = msg.get_payload(decode=True).decode('utf-8', errors='ignore')
except:
pass
return {
'id': email_id,
'subject': subject,
'sender': sender,
'recipient': recipient,
'date': date,
'body': body[:300] # Limit body length
}
def analyze_with_qwen3(email_data, config):
"""Analyze email with local Qwen3 using official library"""
import ollama
import time
prompt = f"""Analyze this email and provide two pieces of information:
1. Is this an advertisement/promotional email?
2. Summarize the email in one sentence
Email details:
Subject: {email_data['subject']}
Sender: {email_data['sender']}
Body: {email_data['body'][:300]}
Respond in this exact format:
IsAD: [YES or NO]
Summary: [one sentence summary]
Reason: [brief explanation]
"""
start_time = time.time()
model = config['ollama'].get('model', 'qwen3:4b')
try:
response = ollama.generate(model=model, prompt=prompt, options={'temperature': 0.1})
output = response['response']
# Parse output
is_ad = False
summary = "No summary"
reason = "Unknown"
for line in output.strip().split('\n'):
if line.startswith('IsAD:'):
is_ad = 'YES' in line.upper()
elif line.startswith('Summary:'):
summary = line.replace('Summary:', '').strip()[:200]
elif line.startswith('Reason:'):
reason = line.replace('Reason:', '').strip()
if is_ad:
result = f"AD: {reason}"
else:
result = f"KEEP: {reason}"
except Exception as e:
result = f"KEEP: error - {str(e)[:100]}"
summary = "Analysis failed"
is_ad = False
duration = time.time() - start_time
return result, summary, is_ad, duration
def move_to_trash(mail, email_id):
"""Move email to Trash folder"""
# Copy to Trash
result = mail.copy(email_id, 'Trash')
if result[0] == 'OK':
# Mark original as deleted
mail.store(email_id, '+FLAGS', '\\Deleted')
return True
return False
def log_result(log_file, email_data, analysis, action, duration=None):
"""Log processing result with Qwen3 duration"""
timestamp = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
duration_str = f" ({duration:.1f}s)" if duration else ""
with open(log_file, 'a') as f:
f.write(f"[{timestamp}] {action}{duration_str}: {email_data['subject'][:60]}\n")
f.write(f" From: {email_data['sender']}\n")
f.write(f" Analysis: {analysis}\n\n")
def load_pending():
"""Load pending emails from JSON file"""
if not PENDING_FILE.exists():
return {}
with open(PENDING_FILE, 'r', encoding='utf-8') as f:
return json.load(f)
def save_pending(pending):
"""Save pending emails to JSON file"""
DATA_DIR.mkdir(exist_ok=True)
with open(PENDING_FILE, 'w', encoding='utf-8') as f:
json.dump(pending, f, indent=2, ensure_ascii=False)
def add_to_pending(email_data, summary, imap_uid, recipient):
"""Add email to pending queue"""
pending = load_pending()
# Generate unique ID
import hashlib
msg_id = f"msg_{hashlib.md5(f'{imap_uid}_{email_data['subject']}'.encode()).hexdigest()[:8]}"
# Extract date from email
email_date = email_data.get('date', datetime.now().isoformat())
pending[msg_id] = {
"imap_uid": str(imap_uid),
"subject": email_data['subject'],
"sender": email_data['sender'],
"recipient": recipient,
"summary": summary,
"email_date": email_date,
"status": "pending",
"found_at": datetime.now().isoformat()
}
save_pending(pending)
return msg_id
def main():
"""Main processing function"""
print("📧 Email Processor Starting...")
# Load config
config = load_config()
# Setup logging
LOGS_DIR.mkdir(exist_ok=True)
log_file = LOGS_DIR / f"{datetime.now().strftime('%Y-%m-%d')}.log"
try:
# Connect to IMAP
print("Connecting to IMAP...")
mail = connect_imap(config)
print("✅ Connected")
# Get unseen emails
email_ids = get_unseen_emails(mail)
print(f"Found {len(email_ids)} unread emails")
if not email_ids:
print("No new emails to process")
mail.logout()
return
# Process each email
processed = 0
moved_to_trash = 0
added_to_pending = 0
for email_id in email_ids:
print(f"\nProcessing email {email_id.decode()}...")
# Fetch email
email_data = fetch_email(mail, email_id)
print(f" Subject: {email_data['subject'][:50]}")
# Analyze with Qwen3 (one call for both ad detection and summary)
analysis, summary, is_ad, duration = analyze_with_qwen3(email_data, config)
print(f" Analysis: {analysis[:100]}")
print(f" Summary: {summary[:60]}...")
print(f" Qwen3 time: {duration:.1f}s")
# Check if analysis was successful (not an error)
if 'error -' in analysis.lower():
# Analysis failed - keep email unread for retry
print(f" -> Analysis failed, keeping unread for retry")
log_result(log_file, email_data, analysis, "FAILED_RETRY", duration)
# Don't increment processed count - will retry next time
continue
# Analysis successful - determine action
if is_ad:
print(" -> Moving to Trash")
if move_to_trash(mail, email_id):
log_result(log_file, email_data, analysis, "MOVED_TO_TRASH", duration)
moved_to_trash += 1
else:
log_result(log_file, email_data, analysis, "MOVE_FAILED", duration)
else:
# Non-ad email - add to pending queue
print(" -> Adding to pending queue")
# Add to pending
msg_internal_id = add_to_pending(
email_data,
summary,
email_id.decode(),
email_data.get('recipient', 'youlu@luyanxin.com')
)
# Mark as read (so it won't be processed again)
mail.store(email_id, '+FLAGS', '\\Seen')
log_result(log_file, email_data, analysis, f"ADDED_TO_PENDING ({msg_internal_id})", duration)
added_to_pending += 1
processed += 1
# Expunge deleted emails
mail.expunge()
mail.logout()
# Summary
print(f"\n{'='*50}")
print(f"Total emails checked: {len(email_ids)}")
print(f"Successfully processed: {processed} emails")
print(f" - Moved to trash (ads): {moved_to_trash}")
print(f" - Added to pending queue: {added_to_pending}")
print(f"Failed (will retry next time): {len(email_ids) - processed}")
print(f"\n📁 Pending queue: {PENDING_FILE}")
print(f"📝 Log: {log_file}")
print(f"\n💡 Run 'python process_queue.py' to view and process pending emails")
except Exception as e:
print(f"❌ Error: {e}")
sys.exit(1)
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,28 @@
#!/usr/bin/env python3
"""Move specific email to trash"""
import imaplib
import email
# Connect
mail = imaplib.IMAP4_SSL('imap.migadu.com', 993)
mail.login('youlu@luyanxin.com', 'kDkNau2r7m.hV!uk*D4Yr8mC7Dyjx9T')
mail.select('INBOX')
# Search for the email with "10% off" in subject
_, search_data = mail.search(None, 'SUBJECT', '"10% off"')
email_ids = search_data[0].split()
print(f"Found {len(email_ids)} emails with '10% off' in subject")
for email_id in email_ids:
# Copy to Trash
result = mail.copy(email_id, 'Trash')
if result[0] == 'OK':
mail.store(email_id, '+FLAGS', '\\Deleted')
print(f"✅ Moved email {email_id.decode()} to Trash")
else:
print(f"❌ Failed to move email {email_id.decode()}")
mail.expunge()
mail.logout()
print("Done!")

View File

@@ -0,0 +1,214 @@
#!/usr/bin/env python3
"""
Email Queue Processor - Handle user commands for pending emails
Reads pending_emails.json and executes user commands (archive/keep/reply)
"""
import json
import imaplib
import os
import sys
from datetime import datetime
from pathlib import Path
SCRIPT_DIR = Path(__file__).parent
DATA_FILE = SCRIPT_DIR / "data" / "pending_emails.json"
def load_pending():
"""Load pending emails from JSON file"""
if not DATA_FILE.exists():
return {}
with open(DATA_FILE, 'r', encoding='utf-8') as f:
return json.load(f)
def save_pending(pending):
"""Save pending emails to JSON file"""
DATA_FILE.parent.mkdir(exist_ok=True)
with open(DATA_FILE, 'w', encoding='utf-8') as f:
json.dump(pending, f, indent=2, ensure_ascii=False)
def connect_imap(config):
"""Connect to IMAP server"""
mail = imaplib.IMAP4_SSL(config['imap']['host'], config['imap']['port'])
mail.login(config['imap']['email'], config['imap']['password'])
return mail
def show_pending_list():
"""Display all pending emails"""
pending = load_pending()
if not pending:
print("📭 没有待处理的邮件")
return
print(f"\n📧 待处理邮件列表 ({len(pending)} 封)")
print("=" * 60)
# Sort by email_date
sorted_items = sorted(
pending.items(),
key=lambda x: x[1].get('email_date', '')
)
for msg_id, data in sorted_items:
if data.get('status') == 'pending':
print(f"\n🆔 {msg_id}")
print(f" 主题: {data.get('subject', 'N/A')[:50]}")
print(f" 发件人: {data.get('sender', 'N/A')}")
print(f" 收件人: {data.get('recipient', 'N/A')}")
print(f" 时间: {data.get('email_date', 'N/A')}")
print(f" 摘要: {data.get('summary', 'N/A')[:80]}")
print("\n" + "=" * 60)
print("\n可用指令:")
print(" • 归档 [ID] - 移动到 Archive 文件夹")
print(" • 保留 [ID] - 标记已读,留在收件箱")
print(" • 删除 [ID] - 移动到 Trash")
print(" • 全部处理 - 列出所有并批量操作")
def archive_email(config, msg_id):
"""Archive a specific email by ID"""
pending = load_pending()
if msg_id not in pending:
print(f"❌ 未找到邮件 ID: {msg_id}")
return False
email_data = pending[msg_id]
uid = email_data.get('imap_uid')
if not uid:
print(f"❌ 邮件 {msg_id} 没有 UID")
return False
try:
mail = connect_imap(config)
mail.select('INBOX')
# Copy to Archive
result = mail.copy(uid, 'Archive')
if result[0] == 'OK':
# Mark original as deleted
mail.store(uid, '+FLAGS', '\\Deleted')
mail.expunge()
# Update status
pending[msg_id]['status'] = 'done'
pending[msg_id]['action'] = 'archived'
pending[msg_id]['processed_at'] = datetime.now().isoformat()
save_pending(pending)
print(f"✅ 已归档: {email_data.get('subject', 'N/A')[:40]}")
return True
else:
print(f"❌ 归档失败: {result}")
return False
except Exception as e:
print(f"❌ 错误: {e}")
return False
finally:
try:
mail.logout()
except:
pass
def keep_email(config, msg_id):
"""Keep email in inbox, mark as read"""
pending = load_pending()
if msg_id not in pending:
print(f"❌ 未找到邮件 ID: {msg_id}")
return False
email_data = pending[msg_id]
uid = email_data.get('imap_uid')
if not uid:
print(f"❌ 邮件 {msg_id} 没有 UID")
return False
try:
mail = connect_imap(config)
mail.select('INBOX')
# Mark as read (Seen)
mail.store(uid, '+FLAGS', '\\Seen')
# Update status
pending[msg_id]['status'] = 'done'
pending[msg_id]['action'] = 'kept'
pending[msg_id]['processed_at'] = datetime.now().isoformat()
save_pending(pending)
print(f"✅ 已保留: {email_data.get('subject', 'N/A')[:40]}")
return True
except Exception as e:
print(f"❌ 错误: {e}")
return False
finally:
try:
mail.logout()
except:
pass
def delete_email(config, msg_id):
"""Move email to Trash"""
pending = load_pending()
if msg_id not in pending:
print(f"❌ 未找到邮件 ID: {msg_id}")
return False
email_data = pending[msg_id]
uid = email_data.get('imap_uid')
if not uid:
print(f"❌ 邮件 {msg_id} 没有 UID")
return False
try:
mail = connect_imap(config)
mail.select('INBOX')
# Copy to Trash
result = mail.copy(uid, 'Trash')
if result[0] == 'OK':
mail.store(uid, '+FLAGS', '\\Deleted')
mail.expunge()
# Update status
pending[msg_id]['status'] = 'done'
pending[msg_id]['action'] = 'deleted'
pending[msg_id]['processed_at'] = datetime.now().isoformat()
save_pending(pending)
print(f"✅ 已删除: {email_data.get('subject', 'N/A')[:40]}")
return True
else:
print(f"❌ 删除失败: {result}")
return False
except Exception as e:
print(f"❌ 错误: {e}")
return False
finally:
try:
mail.logout()
except:
pass
def main():
"""Main function - show pending list"""
import json
# Load config
config_file = Path(__file__).parent / "config.json"
with open(config_file) as f:
config = json.load(f)
show_pending_list()
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,38 @@
#!/usr/bin/env python3
"""Test single email analysis"""
import requests
import json
email_data = {
"subject": "Fwd: Get 10% off your next order 🎉",
"sender": "crac1017@hotmail.com",
"body": "Get 10% off your next order! Limited time offer. Shop now and save!"
}
prompt = f"""Analyze this email and determine if it's an advertisement/promotional email.
Subject: {email_data['subject']}
Sender: {email_data['sender']}
Body preview: {email_data['body'][:200]}
Is this an advertisement or promotional email? Answer with ONLY:
- "AD: [brief reason]" if it's an ad/promo
- "KEEP: [brief reason]" if it's important/legitimate
Be conservative - only mark as AD if clearly promotional."""
print("Sending to Qwen3...")
try:
response = requests.post(
"http://localhost:11434/api/generate",
json={
"model": "qwen3:4b",
"prompt": prompt,
"stream": False
},
timeout=120
)
result = response.json()
print(f"Result: {result.get('response', 'error')}")
except Exception as e:
print(f"Error: {e}")

View File

@@ -0,0 +1 @@
python3

View File

@@ -0,0 +1 @@
/usr/bin/python3

View File

@@ -0,0 +1 @@
python3

View File

@@ -0,0 +1 @@
lib

View File

@@ -0,0 +1,5 @@
home = /usr/bin
include-system-site-packages = false
version = 3.12.3
executable = /usr/bin/python3.12
command = /usr/bin/python3 -m venv /home/lyx/.openclaw/workspace/scripts/email_processor/venv