Files
weval-l99/wevialife-ai-classify.php
2026-04-15 01:38:46 +02:00

123 lines
5.2 KiB
PHP

<?php
/**
* WEVIA Life AI Email Classifier
* Uses Sovereign API to classify emails with LLM
* Called by wevialife-sync.php for new emails
* Also runnable standalone to reclassify recent unclassified emails
*/
$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");
$SOVEREIGN = 'http://127.0.0.1:4000/v1/chat/completions';
$SYSTEM_PROMPT = 'Tu es un classificateur email pour le CEO de WEVAL Consulting, cabinet de consulting tech au Maroc (emarketing, partenariats Vistex/Scaleway/Arrow/Huawei, IA souveraine, campagnes HCP pharma avec Ethica).
Contacts VIP: Olga Vanurina (Vistex), Kaouther Najar (Ethica), Cedric Jarnias, Ray Wu/Chris Cen (Huawei), Omar Belchkar/Julien Bossu (Arrow/Scaleway), Cheikh Gassama (Scaleway), Joe Golemba/Udo Hannemann (Vistex), Ella Scarlett (CX3 Ads).
Reponds UNIQUEMENT en JSON valide sans backticks markdown:
{"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|false,"summary":"resume en 1 phrase francais"}
Regles STRICTES:
- Contacts VIP (Olga,Kaouther,Cedric,Ray,Chris,Omar,Julien,Cheikh,Joe,Udo,Ella) = urgency >= 7, do_first
- Emails partnership/proposal/contract = opportunity, urgency 6-8
- Newsletters/promos/affiliate programs/marketing = newsletter, urgency 1-2, eliminate. JAMAIS do_first pour des promos
- Notifications auto (OVHcloud renewed, server created, 2FA code) = transactional, urgency 1-3, eliminate
- Payment WARNING/suspension/impaye = risk, urgency 8-10, do_first
- Payment CONFIRMED/received/renewed = transactional, urgency 2-3, schedule
- Spam/cold outreach/recrutement = spam, urgency 1, eliminate
- Action Required de services utilises (Optizmo, CX3, partenaires actifs) = action_required, urgency 6-7';
function classify_email($from, $subject, $sovereign_url, $system_prompt) {
$user_msg = "From: $from\nSubject: $subject";
$payload = json_encode([
'messages' => [
['role' => 'system', 'content' => $system_prompt],
['role' => 'user', 'content' => $user_msg]
],
'max_tokens' => 200,
'stream' => false
]);
$ch = curl_init($sovereign_url);
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => ['Content-Type: application/json'],
CURLOPT_POSTFIELDS => $payload,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 12
]);
$resp = curl_exec($ch);
$err = curl_error($ch);
curl_close($ch);
if ($err || !$resp) return null;
$data = json_decode($resp, true);
$content = $data['choices'][0]['message']['content'] ?? '';
// Clean markdown backticks if present
$content = preg_replace('/```json\s*|```\s*/', '', trim($content));
$result = json_decode($content, true);
if (!$result || !isset($result['urgency_score'])) return null;
return $result;
}
// MODE: Reclassify recent emails that have urgency_score <= 1 or category='fyi'/'unknown'
$mode = $argv[1] ?? 'reclassify';
$days = intval($argv[2] ?? 7);
$limit = intval($argv[3] ?? 50);
if ($mode === 'reclassify') {
echo date('H:i:s') . " RECLASSIFY: last $days days, max $limit emails\n";
$stmt = $pdo->query("SELECT id, from_email, from_name, subject
FROM email_classifications
WHERE (urgency_score IS NULL OR urgency_score <= 1)
AND category IN ('fyi','unknown','newsletter')
AND received_at > NOW() - INTERVAL '$days days'
AND (resolved IS NULL OR resolved = false)
ORDER BY received_at DESC
LIMIT $limit");
$emails = $stmt->fetchAll(PDO::FETCH_ASSOC);
echo date('H:i:s') . " Found " . count($emails) . " emails to reclassify\n";
$update = $pdo->prepare("UPDATE email_classifications
SET category = ?, urgency_score = ?, importance_score = ?,
eisenhower_quadrant = ?, requires_action = ?, summary = ?,
classified_at = NOW()
WHERE id = ?");
$classified = 0;
$upgraded = 0;
foreach ($emails as $e) {
$from = $e['from_name'] . ' <' . $e['from_email'] . '>';
$result = classify_email($from, $e['subject'], $SOVEREIGN, $SYSTEM_PROMPT);
if (!$result) {
echo " SKIP #{$e['id']}: LLM failed\n";
continue;
}
$update->execute([
$result['category'] ?? 'fyi',
$result['urgency_score'] ?? 1,
$result['importance_score'] ?? 1,
$result['eisenhower'] ?? 'schedule',
($result['requires_action'] ?? false) ? 't' : 'f',
$result['summary'] ?? $e['subject'],
$e['id']
]);
$classified++;
if (($result['urgency_score'] ?? 1) >= 6) {
$upgraded++;
echo " URGENT #{$e['id']}: {$e['from_name']} - {$e['subject']} => urgency={$result['urgency_score']}\n";
}
usleep(200000); // 200ms between calls to not overload
}
echo date('H:i:s') . " DONE: classified=$classified, upgraded_to_urgent=$upgraded\n";
}