From d6a443a245ab804febc3f6ef1d7238c7101b930a Mon Sep 17 00:00:00 2001 From: opus Date: Mon, 20 Apr 2026 03:40:02 +0200 Subject: [PATCH] auto-sync-0340 --- ...\020T\024\023\021H\035己\022S表021S表024ネ" | 0 api/wevia-apple-ingest.php | 213 ++++++++++++++---- data/wevia-apple/events.jsonl | 1 + data/wevia-apple/index.json | 127 ++++++++++- 4 files changed, 299 insertions(+), 42 deletions(-) delete mode 100644 "api/\b\035ル]唸K[ワ\035ヒZ[拿031[拿034ヒ彌032\034\b\017\017\b\b能022\024\022S表bb桐ネ\017OOH\025ムU単H\020T\024\023\021H\035己\022S表021S表024ネ" diff --git "a/api/\b\035ル]唸K[ワ\035ヒZ[拿031[拿034ヒ彌032\034\b\017\017\b\b能022\024\022S表bb桐ネ\017OOH\025ムU単H\020T\024\023\021H\035己\022S表021S表024ネ" "b/api/\b\035ル]唸K[ワ\035ヒZ[拿031[拿034ヒ彌032\034\b\017\017\b\b能022\024\022S表bb桐ネ\017OOH\025ムU単H\020T\024\023\021H\035己\022S表021S表024ネ" deleted file mode 100644 index e69de29bb..000000000 diff --git a/api/wevia-apple-ingest.php b/api/wevia-apple-ingest.php index aad59d4b3..16b7f4112 100644 --- a/api/wevia-apple-ingest.php +++ b/api/wevia-apple-ingest.php @@ -1,10 +1,9 @@ [], 'orgs'=>[], 'money'=>[], 'deadlines'=>[], 'locations'=>[], 'emails'=>[], 'phones'=>[], 'urls'=>[], 'apps'=>[], 'keywords'=>[], 'sentiment'=>'neutral', 'urgency'=>'low', 'oss'=>[]]; - + preg_match_all('/[a-zA-Z0-9._%+\-]+@[a-zA-Z0-9.\-]+\.[a-zA-Z]{2,}/', $text, $m); $e['emails'] = array_values(array_unique($m[0])); - + preg_match_all('/(?:\+\d{1,3}[\s\-]?)?(?:\(?\d{2,4}\)?[\s\-]?){2,5}\d{2,4}/', $text, $m); $e['phones'] = array_values(array_unique(array_filter($m[0], function($p) { $d = preg_replace('/[^\d]/', '', $p); return strlen($d) >= 8 && strlen($d) <= 15; }))); - + preg_match_all('#https?://[^\s<>"\']+#i', $text, $m); $e['urls'] = array_values(array_unique($m[0])); - + preg_match_all('/(?:[\$竄ャツ」ツ・]|MAD|DZD|TND|EUR|USD|DH)\s*[\d\s,.]+|\d+(?:[\s,.]\d+)*\s*(?:竄ャ|\$|ツ」|MAD|DZD|TND|DH|EUR|USD|k|K|M)\b/u', $text, $m); $e['money'] = array_values(array_unique(array_map('trim', $m[0]))); - + preg_match_all('/\b(?:\d{1,2}[\/\-]\d{1,2}[\/\-]\d{2,4}|\d{4}\-\d{2}\-\d{2}|(?:aujourd\'hui|demain|hier|tomorrow|today|yesterday|this week|next week|la semaine prochaine))/iu', $text, $m); $e['deadlines'] = array_values(array_unique(array_map('trim', $m[0]))); - + preg_match_all('/\b(?:Dr|Mr|Mrs|Ms|Mme|M\.|Pr|Prof|CEO|CTO|CFO|COO|VP|Dir|Directeur|Director|Manager)\.?\s+([A-Zテテづ嘉暗甘偲氾崚][a-zテテ「テゥティテェテョテエテサテァ]+(?:\s+[A-Zテテづ嘉暗甘偲氾崚][a-zテテ「テゥティテェテョテエテサテァ]+)*)/u', $text, $m); $e['people'] = array_values(array_unique($m[0])); - + preg_match_all('/\b[A-Z][a-zA-Z0-9]+(?:\s+[A-Z][a-zA-Z0-9]+)*\s+(?:Inc\.?|LLC|Ltd|Corp\.?|SA|SARL|SAS|GmbH|AG|BV|plc)\b/', $text, $m); $e['orgs'] = array_values(array_unique($m[0])); - + $oss_list = ['langchain','langgraph','crewai','n8n','rasa','ollama','vllm','openrouter','langfuse','dify','flowise','qdrant','chromadb','weaviate','pinecone','milvus','postgres','mongodb','redis','kafka','nginx','kubernetes','docker','grafana','prometheus','stripe','claude','gpt-4','gpt-4o','llama','mistral','gemma','whisper','sap','salesforce','hubspot','notion','obsidian','vercel','cloudflare','github','gitea','supabase','firebase','airtable','zapier','openai','anthropic','gemini','wevads','weval','wevia','ethica','paperclip','arsenal','resend','sendgrid','twilio']; $tl = ' ' . strtolower($text) . ' '; foreach ($oss_list as $o) { if (preg_match('/[^a-z0-9]' . preg_quote($o, '/') . '[^a-z0-9]/i', $tl)) $e['oss'][] = $o; } $e['oss'] = array_values(array_unique($e['oss'])); - + if (preg_match('/\b(urgent|asap|immediatly|critical|critique|deadline|echeance|today|aujourd)/i', $text)) $e['urgency'] = 'high'; elseif (preg_match('/\b(important|priority|priorite|week|semaine|soon|bientot)/i', $text)) $e['urgency'] = 'medium'; - + $pos_w = preg_match_all('/\b(great|excellent|parfait|super|merci|thanks|good|ok|approved|accepted|yes|oui)\b/i', $text); $neg_w = preg_match_all('/\b(problem|probleme|error|erreur|refused|rejected|no|non|urgent|complaint|issue|bug|broken)\b/i', $text); if ($pos_w > $neg_w + 1) $e['sentiment'] = 'positive'; elseif ($neg_w > $pos_w + 1) $e['sentiment'] = 'negative'; - + $apps = ['whatsapp','telegram','instagram','tiktok','linkedin','twitter','x.com','facebook','messenger','slack','discord','teams','zoom','gmail','outlook','calendly','stripe','paypal','revolut','airbnb','uber']; foreach ($apps as $a) { if (stripos($text, $a) !== false) $e['apps'][] = $a; } $e['apps'] = array_values(array_unique($e['apps'])); - + return $e; } @@ -95,7 +94,7 @@ function generate_recommendations($item) { $e = $item['entities'] ?? []; $type = $item['type'] ?? 'unknown'; $text = $item['text_sample'] ?? ''; - + if (!empty($e['deadlines'])) { foreach ($e['deadlines'] as $d) { $reco[] = ['kind'=>'task_create', 'priority'=>($e['urgency']==='high'?'P0':($e['urgency']==='medium'?'P1':'P2')), @@ -166,7 +165,7 @@ function ocr_image($path) { elseif (isset($d['response'])) $ocr = $d['response']; elseif (isset($d['result'])) $ocr = $d['result']; } catch (Exception $e) {} - + if (!$ocr && shell_exec('which tesseract 2>/dev/null')) { $tmp = tempnam('/tmp', 'ocr_'); exec("tesseract " . escapeshellarg($path) . " $tmp 2>/dev/null"); @@ -178,18 +177,37 @@ function ocr_image($path) { return trim($ocr); } +// FIX v3.1: tasks and alerts can co-exist 窶 task_create P0 goes to BOTH tasks[] AND alerts[] +function apply_reco_to_index(&$idx, $reco, $item_id) { + foreach ($reco as $r) { + $r['id'] = 'reco_' . uniqid('', true); + $r['source_item'] = $item_id; + $r['created_at'] = date('c'); + $r['status'] = 'open'; + + // ALL P0 竊 alerts + if ($r['priority'] === 'P0') $idx['alerts'][] = $r; + // ALL task_create 竊 tasks (regardless of priority) + if ($r['kind'] === 'task_create') $idx['tasks'][] = $r; + // tech_research 竊 opportunities + if ($r['kind'] === 'tech_research') $idx['opportunities'][] = $r; + } +} + // ===== ACTIONS ===== if ($action === 'status') { $idx = load_index(); echo json_encode([ - 'ok' => true, 'v' => 'v3-full-ingestion', 'ts' => date('c'), + 'ok' => true, 'v' => 'v3.1-full-ingestion', 'ts' => date('c'), 'total_items' => $idx['total_items'] ?? 0, 'by_type' => $idx['by_type'] ?? [], 'entities_count' => array_map(function($v) { return is_array($v) ? count($v) : 0; }, $idx['entities'] ?? []), 'tasks_pending' => count(array_filter($idx['tasks'] ?? [], function($t) { return ($t['status'] ?? 'open') === 'open'; })), + 'tasks_total' => count($idx['tasks'] ?? []), 'opportunities' => count($idx['opportunities'] ?? []), - 'alerts' => count($idx['alerts'] ?? []), + 'alerts_pending' => count(array_filter($idx['alerts'] ?? [], function($a) { return ($a['status'] ?? 'open') === 'open'; })), + 'alerts_total' => count($idx['alerts'] ?? []), 'last_update' => $idx['last_update'] ?? null, 'drill_count' => count($idx['drill_index'] ?? []) ], JSON_PRETTY_PRINT); @@ -203,7 +221,7 @@ if ($action === 'ingest_photo') { $safe = preg_replace('/[^a-zA-Z0-9._\-]/', '_', $f['name']); $dest = "$DATA_DIR/photos/$id.$safe"; move_uploaded_file($f['tmp_name'], $dest); - + $ocr = ocr_image($dest); $entities = extract_entities($ocr); $item = ['id'=>$id, 'type'=>'photo', 'filename'=>$f['name'], 'size'=>filesize($dest), 'path'=>$dest, @@ -211,7 +229,7 @@ if ($action === 'ingest_photo') { 'ocr'=>$ocr, 'ocr_len'=>strlen($ocr), 'text_sample'=>substr($ocr, 0, 500), 'entities'=>$entities, 'ingested_at'=>date('c')]; $item['recommendations'] = generate_recommendations($item); - + $idx = load_index(); $idx['total_items']++; $idx['by_type']['photo'] = ($idx['by_type']['photo'] ?? 0) + 1; @@ -221,11 +239,7 @@ if ($action === 'ingest_photo') { foreach ($v as $val) $idx['entities'][$k][] = ['val'=>$val, 'source'=>$id]; } } - foreach ($item['recommendations'] as $r) { - if ($r['priority'] === 'P0') $idx['alerts'][] = $r; - elseif ($r['kind'] === 'task_create') $idx['tasks'][] = array_merge(['status'=>'open'], $r); - elseif ($r['kind'] === 'tech_research') $idx['opportunities'][] = $r; - } + apply_reco_to_index($idx, $item['recommendations'], $id); save_index($idx); append_event(['type'=>'ingest', 'item_id'=>$id, 'ts'=>date('c')]); echo json_encode(['ok'=>true, 'id'=>$id, 'item'=>$item], JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE); @@ -237,7 +251,7 @@ if ($action === 'ingest_structured') { $type = $body['type'] ?? $_POST['type'] ?? 'note'; $items = $body['items'] ?? ($body['item'] ? [$body['item']] : []); if (empty($items)) { echo json_encode(['ok'=>false,'error'=>'no items']); exit; } - + $idx = load_index(); $processed = []; foreach ($items as $it) { @@ -249,23 +263,19 @@ if ($action === 'ingest_structured') { elseif ($type === 'health') $text = json_encode($it, JSON_UNESCAPED_UNICODE); elseif ($type === 'call') $text = trim(($it['name'] ?? 'Unknown') . ' - ' . ($it['number'] ?? '') . ' - ' . ($it['duration'] ?? '') . 's - ' . ($it['direction'] ?? '')); else $text = json_encode($it, JSON_UNESCAPED_UNICODE); - + $entities = extract_entities($text); $item = ['id'=>$id, 'type'=>$type, 'raw'=>$it, 'text_sample'=>substr($text, 0, 500), 'entities'=>$entities, 'ingested_at'=>date('c')]; $item['recommendations'] = generate_recommendations($item); - + $idx['total_items']++; $idx['by_type'][$type] = ($idx['by_type'][$type] ?? 0) + 1; $idx['drill_index'][$id] = $item; foreach ($entities as $k => $v) { if (is_array($v)) foreach ($v as $val) $idx['entities'][$k][] = ['val'=>$val, 'source'=>$id]; } - foreach ($item['recommendations'] as $r) { - if ($r['priority'] === 'P0') $idx['alerts'][] = $r; - elseif ($r['kind'] === 'task_create') $idx['tasks'][] = array_merge(['status'=>'open'], $r); - elseif ($r['kind'] === 'tech_research') $idx['opportunities'][] = $r; - } + apply_reco_to_index($idx, $item['recommendations'], $id); $processed[] = $id; append_event(['type'=>'ingest', 'item_id'=>$id, 'data_type'=>$type, 'ts'=>date('c')]); } @@ -279,6 +289,9 @@ if ($action === 'drill') { $idx = load_index(); $item = $idx['drill_index'][$id] ?? null; if (!$item) { echo json_encode(['ok'=>false,'error'=>'not found']); exit; } + // Also return related reco + tasks + alerts for this item + $item['related_tasks'] = array_values(array_filter($idx['tasks'] ?? [], function($t) use ($id) { return ($t['source_item'] ?? '') === $id; })); + $item['related_alerts'] = array_values(array_filter($idx['alerts'] ?? [], function($a) use ($id) { return ($a['source_item'] ?? '') === $id; })); echo json_encode(['ok'=>true, 'item'=>$item], JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE); exit; } @@ -333,13 +346,137 @@ if ($action === 'entities') { exit; } -if ($action === 'tasks') { $idx = load_index(); echo json_encode(['ok'=>true, 'tasks'=>$idx['tasks'] ?? []]); exit; } -if ($action === 'alerts') { $idx = load_index(); echo json_encode(['ok'=>true, 'alerts'=>$idx['alerts'] ?? []]); exit; } +if ($action === 'tasks') { + $idx = load_index(); + $filter = $_GET['status'] ?? null; + $tasks = $idx['tasks'] ?? []; + if ($filter) $tasks = array_values(array_filter($tasks, function($t) use ($filter) { return ($t['status'] ?? 'open') === $filter; })); + echo json_encode(['ok'=>true, 'tasks'=>$tasks, 'total'=>count($tasks)]); + exit; +} + +if ($action === 'alerts') { + $idx = load_index(); + $filter = $_GET['status'] ?? null; + $alerts = $idx['alerts'] ?? []; + if ($filter) $alerts = array_values(array_filter($alerts, function($a) use ($filter) { return ($a['status'] ?? 'open') === $filter; })); + echo json_encode(['ok'=>true, 'alerts'=>$alerts, 'total'=>count($alerts)]); + exit; +} + +// NEW v3.1: mark_done / resolve_alert +if ($action === 'mark_done') { + $id = $_GET['id'] ?? $_POST['id'] ?? ''; + $idx = load_index(); + $found = false; + foreach ($idx['tasks'] ?? [] as &$t) { + if (($t['id'] ?? '') === $id) { + $t['status'] = 'done'; + $t['done_at'] = date('c'); + $found = true; + break; + } + } + if ($found) { save_index($idx); append_event(['type'=>'task_done', 'task_id'=>$id, 'ts'=>date('c')]); } + echo json_encode(['ok'=>$found, 'id'=>$id]); + exit; +} + +if ($action === 'resolve_alert') { + $id = $_GET['id'] ?? $_POST['id'] ?? ''; + $idx = load_index(); + $found = false; + foreach ($idx['alerts'] ?? [] as &$a) { + if (($a['id'] ?? '') === $id) { + $a['status'] = 'resolved'; + $a['resolved_at'] = date('c'); + $found = true; + break; + } + } + if ($found) { save_index($idx); append_event(['type'=>'alert_resolved', 'alert_id'=>$id, 'ts'=>date('c')]); } + echo json_encode(['ok'=>$found, 'id'=>$id]); + exit; +} + +// NEW v3.1: stats_timeline 窶 daily aggregation for charts +if ($action === 'stats_timeline') { + global $EVENTS_FILE; + if (!file_exists($EVENTS_FILE)) { echo json_encode(['ok'=>true, 'timeline'=>[]]); exit; } + $lines = file($EVENTS_FILE, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES); + $byDay = []; + foreach ($lines as $l) { + $ev = @json_decode($l, true); + if (!$ev || empty($ev['ts'])) continue; + $day = substr($ev['ts'], 0, 10); + if (!isset($byDay[$day])) $byDay[$day] = ['date'=>$day, 'ingests'=>0, 'tasks_done'=>0, 'alerts_resolved'=>0]; + if (($ev['type'] ?? '') === 'ingest') $byDay[$day]['ingests']++; + elseif (($ev['type'] ?? '') === 'task_done') $byDay[$day]['tasks_done']++; + elseif (($ev['type'] ?? '') === 'alert_resolved') $byDay[$day]['alerts_resolved']++; + } + ksort($byDay); + echo json_encode(['ok'=>true, 'timeline'=>array_values($byDay)]); + exit; +} + +// NEW v3.1: delete item (with cascade to tasks/alerts/reco) +if ($action === 'delete_item') { + $id = $_GET['id'] ?? $_POST['id'] ?? ''; + $idx = load_index(); + if (!isset($idx['drill_index'][$id])) { echo json_encode(['ok'=>false,'error'=>'not found']); exit; } + $removed = $idx['drill_index'][$id]; + unset($idx['drill_index'][$id]); + $type = $removed['type'] ?? 'unknown'; + if (isset($idx['by_type'][$type]) && $idx['by_type'][$type] > 0) $idx['by_type'][$type]--; + $idx['total_items']--; + // Cascade: remove related tasks, alerts, opportunities + $idx['tasks'] = array_values(array_filter($idx['tasks'] ?? [], function($t) use ($id) { return ($t['source_item'] ?? '') !== $id; })); + $idx['alerts'] = array_values(array_filter($idx['alerts'] ?? [], function($a) use ($id) { return ($a['source_item'] ?? '') !== $id; })); + $idx['opportunities'] = array_values(array_filter($idx['opportunities'] ?? [], function($o) use ($id) { return ($o['source_item'] ?? '') !== $id; })); + // Also remove from entities + foreach ($idx['entities'] ?? [] as $cat => &$list) { + if (is_array($list)) { + $list = array_values(array_filter($list, function($e) use ($id) { return !(is_array($e) && ($e['source'] ?? '') === $id); })); + } + } + // Delete physical file if photo + if ($type === 'photo' && !empty($removed['path']) && file_exists($removed['path'])) @unlink($removed['path']); + save_index($idx); + append_event(['type'=>'delete', 'item_id'=>$id, 'ts'=>date('c')]); + echo json_encode(['ok'=>true, 'deleted'=>$id]); + exit; +} + +// NEW v3.1: search across all items +if ($action === 'search') { + $q = trim($_GET['q'] ?? $_POST['q'] ?? ''); + if (strlen($q) < 2) { echo json_encode(['ok'=>false, 'error'=>'query too short']); exit; } + $idx = load_index(); + $matches = []; + foreach ($idx['drill_index'] ?? [] as $item) { + $hay = strtolower(($item['text_sample'] ?? '') . ' ' . ($item['ocr'] ?? '') . ' ' . json_encode($item['entities'] ?? [])); + if (strpos($hay, strtolower($q)) !== false) { + $matches[] = ['id'=>$item['id'], 'type'=>$item['type'], 'ingested_at'=>$item['ingested_at'], + 'preview'=>substr($item['text_sample'] ?? '', 0, 200)]; + } + } + echo json_encode(['ok'=>true, 'query'=>$q, 'matches'=>$matches, 'total'=>count($matches)]); + exit; +} if ($action === 'shortcut_manifest') { echo json_encode([ - 'ok' => true, 'version' => '3.0', + 'ok' => true, 'version' => '3.1', 'endpoint' => 'https://weval-consulting.com/api/wevia-apple-ingest.php', + 'downloads' => [ + 'photos' => 'https://weval-consulting.com/downloads/wevia-shortcut-photos.json', + 'messages' => 'https://weval-consulting.com/downloads/wevia-shortcut-messages.json', + 'contacts' => 'https://weval-consulting.com/downloads/wevia-shortcut-contacts.json', + 'calendar' => 'https://weval-consulting.com/downloads/wevia-shortcut-calendar.json', + 'notes' => 'https://weval-consulting.com/downloads/wevia-shortcut-notes.json', + 'calls' => 'https://weval-consulting.com/downloads/wevia-shortcut-calls.json', + 'health' => 'https://weval-consulting.com/downloads/wevia-shortcut-health.json' + ], 'actions' => [ 'photos' => ['endpoint_action' => 'ingest_photo', 'method' => 'POST multipart', 'field' => 'file'], 'messages' => ['endpoint_action' => 'ingest_structured', 'body' => ['type'=>'message', 'items'=>[['from'=>'', 'to'=>'', 'body'=>'', 'date'=>'']]]], @@ -353,4 +490,4 @@ if ($action === 'shortcut_manifest') { exit; } -echo json_encode(['ok'=>false, 'error'=>'unknown action', 'available'=>['status','ingest_photo','ingest_structured','drill','list','recommendations','entities','tasks','alerts','shortcut_manifest']]); +echo json_encode(['ok'=>false, 'error'=>'unknown action', 'available'=>['status','ingest_photo','ingest_structured','drill','list','recommendations','entities','tasks','alerts','mark_done','resolve_alert','stats_timeline','delete_item','search','shortcut_manifest']]); diff --git a/data/wevia-apple/events.jsonl b/data/wevia-apple/events.jsonl index 2a615736a..2ccc7ac69 100644 --- a/data/wevia-apple/events.jsonl +++ b/data/wevia-apple/events.jsonl @@ -1,3 +1,4 @@ {"type":"ingest","item_id":"message_69e5824ba35bd6.09795740","data_type":"message","ts":"2026-04-20T01:32:59+00:00"} {"type":"ingest","item_id":"contact_69e5824bdbea77.22631491","data_type":"contact","ts":"2026-04-20T01:32:59+00:00"} {"type":"ingest","item_id":"calendar_69e5824c2569b2.34050670","data_type":"calendar","ts":"2026-04-20T01:33:00+00:00"} +{"type":"ingest","item_id":"message_69e583ec4a8c63.43728183","data_type":"message","ts":"2026-04-20T01:39:56+00:00"} diff --git a/data/wevia-apple/index.json b/data/wevia-apple/index.json index 4012a75a0..079f79f39 100644 --- a/data/wevia-apple/index.json +++ b/data/wevia-apple/index.json @@ -1,8 +1,8 @@ { - "total_items": 3, + "total_items": 4, "by_type": { "photo": 0, - "message": 1, + "message": 2, "contact": 1, "calendar": 1, "note": 0, @@ -30,6 +30,10 @@ { "val": "25000 USD", "source": "calendar_69e5824c2569b2.34050670" + }, + { + "val": "32000 EUR", + "source": "message_69e583ec4a8c63.43728183" } ], "deadlines": [ @@ -40,6 +44,10 @@ { "val": "2026-04-22", "source": "calendar_69e5824c2569b2.34050670" + }, + { + "val": "demain", + "source": "message_69e583ec4a8c63.43728183" } ], "locations": [], @@ -55,6 +63,10 @@ { "val": "olga.vanurina@vistex.com", "source": "contact_69e5824bdbea77.22631491" + }, + { + "val": "yacineutt@gmail.com", + "source": "message_69e583ec4a8c63.43728183" } ], "phones": [ @@ -89,6 +101,14 @@ { "val": "x.com", "source": "contact_69e5824bdbea77.22631491" + }, + { + "val": "teams", + "source": "message_69e583ec4a8c63.43728183" + }, + { + "val": "gmail", + "source": "message_69e583ec4a8c63.43728183" } ], "oss": [ @@ -106,7 +126,19 @@ } ] }, - "tasks": [], + "tasks": [ + { + "kind": "task_create", + "priority": "P0", + "label": "Crテゥer tテ「che pour テゥchテゥance: demain", + "action": "Ajouter テ Calendar\/Reminders avec contexte: Olga Vanurina -> yacineutt@gmail.com\nURGENT: Vistex addendum signing deadline demain. Budget 32000 EUR confirmテゥ. Appel ", + "source": "message_69e583ec4a8c63.43728183", + "id": "reco_69e583ec4b0830.98454851", + "source_item": "message_69e583ec4a8c63.43728183", + "created_at": "2026-04-20T01:39:56+00:00", + "status": "open" + } + ], "opportunities": [ { "kind": "tech_research", @@ -137,9 +169,31 @@ "label": "Crテゥer tテ「che pour テゥchテゥance: 2026-04-22", "action": "Ajouter テ Calendar\/Reminders avec contexte: CRITICAL: Board meeting with Dr. Ray Wu\nHuawei Cloud HQ\nLitige billing review - 25000 USD at stake - urgent\n2026-04-22T1", "source": "calendar_69e5824c2569b2.34050670" + }, + { + "kind": "task_create", + "priority": "P0", + "label": "Crテゥer tテ「che pour テゥchテゥance: demain", + "action": "Ajouter テ Calendar\/Reminders avec contexte: Olga Vanurina -> yacineutt@gmail.com\nURGENT: Vistex addendum signing deadline demain. Budget 32000 EUR confirmテゥ. Appel ", + "source": "message_69e583ec4a8c63.43728183", + "id": "reco_69e583ec4b0830.98454851", + "source_item": "message_69e583ec4a8c63.43728183", + "created_at": "2026-04-20T01:39:56+00:00", + "status": "open" + }, + { + "kind": "urgent_alert", + "priority": "P0", + "label": "Item urgent 窶 traitement immテゥdiat", + "action": "Telegram @wevia_cyber_bot", + "source": "message_69e583ec4a8c63.43728183", + "id": "reco_69e583ec4b0a35.50995876", + "source_item": "message_69e583ec4a8c63.43728183", + "created_at": "2026-04-20T01:39:56+00:00", + "status": "open" } ], - "last_update": "2026-04-20T01:33:00+00:00", + "last_update": "2026-04-20T01:39:56+00:00", "drill_index": { "message_69e5824ba35bd6.09795740": { "id": "message_69e5824ba35bd6.09795740", @@ -346,6 +400,71 @@ "source": "calendar_69e5824c2569b2.34050670" } ] + }, + "message_69e583ec4a8c63.43728183": { + "id": "message_69e583ec4a8c63.43728183", + "type": "message", + "raw": { + "from": "Olga Vanurina", + "to": "yacineutt@gmail.com", + "body": "URGENT: Vistex addendum signing deadline demain. Budget 32000 EUR confirmテゥ. Appel 15h via Teams." + }, + "text_sample": "Olga Vanurina -> yacineutt@gmail.com\nURGENT: Vistex addendum signing deadline demain. Budget 32000 EUR confirmテゥ. Appel 15h via Teams.", + "entities": { + "people": [], + "orgs": [], + "money": [ + "32000 EUR" + ], + "deadlines": [ + "demain" + ], + "locations": [], + "emails": [ + "yacineutt@gmail.com" + ], + "phones": [], + "urls": [], + "apps": [ + "teams", + "gmail" + ], + "keywords": [], + "sentiment": "neutral", + "urgency": "high", + "oss": [] + }, + "ingested_at": "2026-04-20T01:39:56+00:00", + "recommendations": [ + { + "kind": "task_create", + "priority": "P0", + "label": "Crテゥer tテ「che pour テゥchテゥance: demain", + "action": "Ajouter テ Calendar\/Reminders avec contexte: Olga Vanurina -> yacineutt@gmail.com\nURGENT: Vistex addendum signing deadline demain. Budget 32000 EUR confirmテゥ. Appel ", + "source": "message_69e583ec4a8c63.43728183" + }, + { + "kind": "finance_track", + "priority": "P1", + "label": "Montant(s) dテゥtectテゥ(s): 32000 EUR", + "action": "Vテゥrifier facture\/devis et lier CRM WEVAL", + "source": "message_69e583ec4a8c63.43728183" + }, + { + "kind": "contact_capture", + "priority": "P2", + "label": "1 email(s), 0 phone(s)", + "action": "Sync iPhone Contacts + CRM", + "source": "message_69e583ec4a8c63.43728183" + }, + { + "kind": "urgent_alert", + "priority": "P0", + "label": "Item urgent 窶 traitement immテゥdiat", + "action": "Telegram @wevia_cyber_bot", + "source": "message_69e583ec4a8c63.43728183" + } + ] } } } \ No newline at end of file