['timeout' => 4, 'header' => "Host: weval-consulting.com\r\n"], 'ssl' => ['verify_peer' => false, 'verify_peer_name' => false] ])); $stats = @json_decode($raw_stats, true); if ($stats && isset($stats['total'])) { @file_put_contents($cache_file, $raw_stats); } } if ($intent === 'stats_hcp' || $intent === 'stats_country' || $intent === 'specialties' || $intent === 'campaigns_stats') { if ($stats && isset($stats['total'])) { $by = $stats['by_country'] ?? []; $ctx = "DONNÉES LIVE Ethica (source PG ethica.medecins_real S95, ts {$stats['ts']}) :\n"; $ctx .= "- Total HCPs : " . number_format($stats['total'], 0, ',', ' ') . "\n"; $ctx .= "- Avec email : " . number_format($stats['with_email'], 0, ',', ' ') . " ({$stats['pct_email']}%)\n"; $ctx .= "- Avec téléphone : " . number_format($stats['with_telephone'], 0, ',', ' ') . " ({$stats['pct_telephone']}%)\n"; $ctx .= "- Gap email : " . number_format($stats['gap_email'], 0, ',', ' ') . " | Gap tel : " . number_format($stats['gap_telephone'], 0, ',', ' ') . "\n"; $ctx .= "Répartition par pays :\n"; foreach ($by as $c) { $ctx .= " - {$c['country']} : " . number_format($c['hcps'], 0, ',', ' ') . " HCPs ({$c['pct_email']}% email, {$c['pct_tel']}% tel)\n"; } $ctx .= "- Campagnes actives : " . ($stats['campaigns'] ?? 0) . "\n"; $ctx .= "- Consent log : " . ($stats['consent_log'] ?? 0) . " opt-ins\n"; $ctx .= "- 30 derniers jours : opens=" . ($stats['last_30d']['opens'] ?? 0) . ", clicks=" . ($stats['last_30d']['clicks'] ?? 0) . ", conversions=" . ($stats['last_30d']['conversions'] ?? 0) . "\n"; $context_data .= $ctx . "\n"; $sources[] = ['url' => '/api/ethica-stats-api.php', 'label' => 'PG ethica.medecins_real live']; } } if ($intent === 'prospects_today') { $pt = @file_get_contents('https://127.0.0.1/api/opus5-prospects-today.php', false, stream_context_create([ 'http' => ['timeout' => 5, 'header' => "Host: weval-consulting.com\r\n"], 'ssl' => ['verify_peer' => false, 'verify_peer_name' => false] ])); $pt_data = @json_decode($pt, true); if ($pt_data && isset($pt_data['response'])) { // Réponse déterministe + on passe à LLM pour enrichir $context_data .= "PROSPECTS AUJOURD'HUI (source admin.leads + weval_leads + ethica live) :\n"; $context_data .= $pt_data['response'] . "\n\n"; $sources[] = ['url' => '/api/opus5-prospects-today.php', 'label' => 'PG direct multi-source']; } } // Vault : Ethica pilot-config (toujours pour RGPD/warmup/campaigns) if (in_array($intent, ['rgpd', 'warmup_strategy', 'campaigns_stats'])) { $pilot = @file_get_contents('/opt/wevads/vault/ethica-pilot-config.json'); $pilot_data = @json_decode($pilot, true); if ($pilot_data) { $context_data .= "CONFIG PILOT Ethica (vault) :\n"; $context_data .= "- Campaign : {$pilot_data['campaign']} (status: {$pilot_data['status']})\n"; $context_data .= "- Cible : {$pilot_data['target']['total_emails']} emails ({$pilot_data['target']['country']}, spécialités : " . implode(', ', $pilot_data['target']['specialties']) . ")\n"; $context_data .= "- Batch size : {$pilot_data['rules']['batch_size']}/jour\n"; $context_data .= "- Consent URL : {$pilot_data['target']['consent_url']}\n"; $context_data .= "- Tracking : {$pilot_data['template']['tracking_domain']}\n\n"; $sources[] = ['url' => 'vault://ethica-pilot-config.json', 'label' => 'Pilot config Ethica']; } } // === 4. SYSTEM PROMPT expert pharma B2B Maghreb === $system_prompt = "Tu es Ethica AI, assistant expert pharma B2B Maghreb (Algérie, Maroc, Tunisie). " . "Tu es spécialisé sur : intelligence HCP (médecins, pharmaciens, dentistes), " . "campagnes email marketing santé, warmup, délivrabilité, RGPD santé, pricing. " . "Style : concis, actionnable, expert. Réponds en français. " . "Si des données live sont fournies dans le contexte, utilise-les exactement (jamais inventer de chiffres). " . "Pour les salutations simples, réponds naturellement et proactif sur ce que tu peux aider."; $llm_input = $system_prompt; if ($context_data) { $llm_input .= "\n\n=== DONNÉES LIVE (utilise UNIQUEMENT ces chiffres, jamais inventer) ===\n" . $context_data; } $llm_input .= "\n\n=== QUESTION USER ===\n" . $user_msg; // === 5. CASCADE LLM via sovereign:4000 DIRECT (13 providers 0€, zéro guard WEVAL/public) === // Raison : wevia-json-api a hardrule "weval" (capture prompt) + public_guard (bloque "warmup"/"rgpd") // qui empêchent Ethica AI de parler de son propre sujet métier. sovereign:4000 = cascade pure. $user_payload = $llm_input; // contient system + context + user_msg $ch = curl_init('http://127.0.0.1:4000/v1/chat/completions'); curl_setopt_array($ch, [ CURLOPT_POST => true, CURLOPT_POSTFIELDS => json_encode([ 'model' => 'auto', 'messages' => [ ['role' => 'system', 'content' => $system_prompt . ($context_data ? "\n\nDONNÉES LIVE FOURNIES (utilise UNIQUEMENT ces chiffres) :\n" . $context_data : '')], ['role' => 'user', 'content' => $user_msg] ], 'max_tokens' => 800, 'temperature' => 0.4 ]), CURLOPT_HTTPHEADER => ['Content-Type: application/json'], CURLOPT_RETURNTRANSFER => true, CURLOPT_TIMEOUT => 20, CURLOPT_CONNECTTIMEOUT => 3 ]); $llm_raw = curl_exec($ch); $http = curl_getinfo($ch, CURLINFO_HTTP_CODE); curl_close($ch); $llm_data = @json_decode($llm_raw, true); // === 6. RESPONSE === $ms = round((microtime(true) - $start) * 1000); // sovereign OpenAI format : choices[0].message.content $response_text = null; $provider_used = 'sovereign-cascade'; if ($llm_data && isset($llm_data['choices'][0]['message']['content'])) { $response_text = $llm_data['choices'][0]['message']['content']; $provider_used = $llm_data['model'] ?? ($llm_data['provider'] ?? 'sovereign'); } if ($response_text) { echo json_encode([ 'response' => $response_text, 'provider' => 'ethica-brain/' . $provider_used, 'intent' => $intent, 'mode' => 'sovereign-4000-direct', 'ms' => $ms, 'sources' => $sources, 'doctrine' => 83 ], JSON_UNESCAPED_UNICODE); exit; } // Fallback gracieux (pas de hardcode, message honnête) echo json_encode([ 'response' => "Je rencontre un ralentissement sur la cascade LLM. Pouvez-vous reformuler votre question ou utiliser un raccourci ci-dessus ? " . "Nos données live sont : {$stats['total']} HCPs Maghreb, {$stats['with_email']} avec email, {$stats['campaigns']} campagnes actives.", 'provider' => 'ethica-brain/fallback', 'intent' => $intent, 'mode' => 'graceful', 'ms' => $ms, 'upstream_http' => $http, 'sources' => $sources, 'doctrine' => 83 ], JSON_UNESCAPED_UNICODE);