98 lines
5.5 KiB
PHP
Executable File
98 lines
5.5 KiB
PHP
Executable File
<?php
|
|
// WEVIA Life Email Sync - Direct IMAP to DB
|
|
// Runs via cron every 30 min
|
|
set_time_limit(120);
|
|
$pdo = new PDO("pgsql:host=127.0.0.1;dbname=wevia_db;options='--search_path=admin,public'", "postgres", "");
|
|
$pdo->exec("SET search_path TO admin,public");
|
|
|
|
$sourcesFile = '/var/www/weval/wevia-ia/wevialife-data/email-sources.json';
|
|
$sources = json_decode(@file_get_contents($sourcesFile) ?: '[]', true) ?: [];
|
|
$log = function($msg) { echo date('H:i:s')." $msg\n"; };
|
|
|
|
$inserted = 0;
|
|
$skipped = 0;
|
|
|
|
foreach ($sources as $s) {
|
|
if (($s['status'] ?? '') !== 'active') continue;
|
|
$pwd = base64_decode($s['password'] ?? '');
|
|
$server = $s['server'] ?? 'server105.web-hosting.com';
|
|
$port = $s['port'] ?? 993;
|
|
$email = $s['email'];
|
|
|
|
foreach (['INBOX'] as $folder) {
|
|
$mb = "{{$server}:{$port}/imap/ssl/novalidate-cert}{$folder}";
|
|
$conn = @imap_open($mb, $email, $pwd, 0, 1);
|
|
if (!$conn) { $log("FAIL $email: ".imap_last_error()); continue; }
|
|
|
|
$info = imap_check($conn);
|
|
$total = $info->Nmsgs;
|
|
$start = max(1, $total - 99); // last 100
|
|
$ov = imap_fetch_overview($conn, "$start:$total", 0);
|
|
|
|
// Get existing UIDs
|
|
$existingUids = [];
|
|
$stmt = $pdo->query("SELECT uid FROM email_classifications WHERE folder='$folder'");
|
|
foreach ($stmt->fetchAll(PDO::FETCH_COLUMN) as $u) $existingUids[$u] = true;
|
|
|
|
$ins = $pdo->prepare("INSERT INTO email_classifications
|
|
(uid, folder, from_email, from_name, subject, received_at, category, eisenhower_quadrant, summary, resolved)
|
|
VALUES (?,?,?,?,?,?,?,?,?,false) ON CONFLICT DO NOTHING");
|
|
|
|
foreach (array_reverse($ov ?: []) as $o) {
|
|
$uid = $o->uid;
|
|
if (isset($existingUids[$uid])) { $skipped++; continue; }
|
|
|
|
$from = isset($o->from) ? mb_decode_mimeheader($o->from) : '';
|
|
$subj = isset($o->subject) ? mb_decode_mimeheader($o->subject) : '';
|
|
$date = isset($o->date) ? date('Y-m-d H:i:s', strtotime($o->date)) : null;
|
|
|
|
// Extract email from "Name <email>" format
|
|
preg_match('/<([^>]+)>/', $from, $m);
|
|
$fromEmail = $m[1] ?? $from;
|
|
$fromName = trim(preg_replace('/<[^>]+>/', '', $from));
|
|
|
|
// AI Classification via Sovereign (Opus wire 15avr)
|
|
$cat = 'fyi'; $quad = 'schedule'; $summary = $subj;
|
|
$urgScore = 1; $impScore = 1; $reqAction = false;
|
|
$isVIP = preg_match('/kaouther|vistex|cedric|ella.*scarlett|cx3|ray.*wu|chris.*cen|huawei|scaleway|arrow|belchkar|gassama|golemba|hannemann/i', $fromName.$fromEmail);
|
|
if ($isVIP) {
|
|
$cat = 'action_required'; $quad = 'do_first'; $urgScore = 10; $impScore = 9; $reqAction = true;
|
|
} else {
|
|
$aiP = json_encode(['messages'=>[['role'=>'system','content'=>'Classificateur email CEO WEVAL. JSON ONLY sans backticks: {"category":"action_required|opportunity|risk|transactional|newsletter|fyi|spam","urgency_score":1-10,"importance_score":1-10,"eisenhower":"do_first|schedule|delegate|eliminate","requires_action":true,"summary":"1 phrase"}. Promos/newsletters=1-2. VIP=7+. Payments=8+.'],['role'=>'user','content'=>"From: $fromName <$fromEmail> Subject: $subj"]],'max_tokens'=>200,'stream'=>false]);
|
|
$aiC = curl_init('http://127.0.0.1:4000/v1/chat/completions');
|
|
curl_setopt_array($aiC, [CURLOPT_POST=>true, CURLOPT_HTTPHEADER=>['Content-Type: application/json'], CURLOPT_POSTFIELDS=>$aiP, CURLOPT_RETURNTRANSFER=>true, CURLOPT_TIMEOUT=>10]);
|
|
$aiR = curl_exec($aiC); curl_close($aiC);
|
|
$aiD = @json_decode($aiR, true);
|
|
$aiT = preg_replace('/```json\s*|```\s*/', '', trim($aiD['choices'][0]['message']['content'] ?? ''));
|
|
$aiJ = @json_decode($aiT, true);
|
|
if ($aiJ && isset($aiJ['urgency_score'])) {
|
|
$cat = $aiJ['category'] ?? 'fyi';
|
|
$urgScore = intval($aiJ['urgency_score']);
|
|
$impScore = intval($aiJ['importance_score'] ?? 1);
|
|
$quad = $aiJ['eisenhower'] ?? 'schedule';
|
|
$reqAction = !empty($aiJ['requires_action']);
|
|
$summary = $aiJ['summary'] ?? $subj;
|
|
} else {
|
|
$sL = strtolower($subj); $fL = strtolower($from);
|
|
if (preg_match('/noreply|newsletter|unsubscribe/i', $fL.$sL)) { $cat='newsletter'; $quad='eliminate'; }
|
|
elseif (preg_match('/urgent|asap|critical/i', $sL)) { $cat='action_required'; $quad='do_first'; $urgScore=7; $reqAction=true; }
|
|
}
|
|
}
|
|
$ins->execute([$uid, $folder, $fromEmail, $fromName, $subj, $date, $cat, $quad, $summary]);
|
|
$pdo->prepare("UPDATE email_classifications SET urgency_score=?, importance_score=?, requires_action=?, classified_at=NOW() WHERE uid=? AND folder=?")->execute([$urgScore, $impScore, $reqAction?'t':'f', $uid, $folder]);
|
|
$inserted++;
|
|
}
|
|
imap_close($conn);
|
|
$log("$email/$folder: total=$total, inserted=$inserted, skipped=$skipped");
|
|
}
|
|
}
|
|
|
|
$log("SYNC DONE: +$inserted new, $skipped existing");
|
|
|
|
// Update stats
|
|
$stats = $pdo->query("SELECT COUNT(*) as total,
|
|
SUM(CASE WHEN eisenhower_quadrant='do_first' THEN 1 ELSE 0 END) as urgent,
|
|
MAX(received_at) as latest
|
|
FROM email_classifications")->fetch(PDO::FETCH_ASSOC);
|
|
$log("DB: {$stats['total']} total, {$stats['urgent']} urgent, latest={$stats['latest']}");
|