Yacine demande via screenshot (WTP dashboard): - Barre/entete prend tout ecran - Faire caroussel rotationnel au lieu du plat DOCTRINE-221 opus-phase79 - 3D Carousel handler: - /var/www/html/api/wevia-ux-carousel-apply.sh (6712B) - Compact header CSS: max-height 72px, padding 8px, h1 1.2rem - 3D perspective: 1600px, scroll-snap-type x mandatory - Focus/prev/next rotation Y 28deg, translateZ, scale dynamic - Toggle button floating bottom-right Grid <-> Carrousel - JS auto-detect main grid container by children count - Scroll listener updates focus class real-time - prefers-reduced-motion respected DOCTRINE-222 opus-phase79 - chat.php triggers: - Added carousel NL triggers to admin_triggers array - Now WEVIA chat routes carousel requests to internal orchestrator Intent stub: - /var/www/html/api/wired-pending/intent-opus4-wevia_ux_carousel_rotation.php - 11 triggers: carrousel 3d, caroussel 3d, rotation, rotationnel, compact header, etc - Priority P1 - cmd extracts PAGE from message Applied: - weval-technology-platform.html: size 457235 -> 462552 (+5317 CSS/JS) - marker DOCTRINE-221 present, HTTP 200 confirmed Pattern: Yacine can now say in chat NL: carrousel 3d wevia-master rotationnel agents-alive compact header all-ia-hub -> WEVIA applies 3D carousel autonomously Cumul session Opus: - 75 tags - 56 doctrines (146-222) - 22 Gemini + 2 Minority Report + 1 Carrousel 3D - NR 153/153 invariant 79 phases
197 lines
9.9 KiB
PHP
197 lines
9.9 KiB
PHP
<?php
|
|
// WEVIA Chat V52 - Orchestrator-first + capability detection
|
|
// V52 17avr: detect CAPABILITY keywords (code/schema/pdf/react/svg/mermaid)
|
|
// → if capability detected = skip orchestrator, go direct to LLM with capable prompt
|
|
// → else if business intent match = orchestrator data reelle
|
|
// → else LLM fallback (v3)
|
|
header('Content-Type: application/json');
|
|
header('Access-Control-Allow-Origin: *');
|
|
header('Access-Control-Allow-Headers: Content-Type');
|
|
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') { http_response_code(200); exit; }
|
|
|
|
$input = json_decode(file_get_contents('php://input'), true);
|
|
$msg = trim($input['message'] ?? $input['msg'] ?? $input['text'] ?? '');
|
|
if (!$msg) { echo json_encode(['response' => 'Message vide', 'provider' => 'error']); exit; }
|
|
|
|
$msg_lower = mb_strtolower($msg);
|
|
|
|
// === V52 CAPABILITY DETECTION ===
|
|
// If query asks for code/schema/document GENERATION, skip orchestrator
|
|
$capability_keywords = [
|
|
'react', 'composant', 'component', 'typescript', 'jsx', 'tsx',
|
|
'mermaid', 'svg', 'schema', 'schéma', 'diagramme', 'architecture',
|
|
'pdf', 'document', 'cahier.*charges', 'specs?\b', 'spécifications?',
|
|
'dessine', 'draw', 'genere.*pdf', 'genere.*schema', 'genere.*code',
|
|
'redige', 'rédige', 'ecris.*code', 'écris.*code', 'write.*code',
|
|
'python|javascript|php|sql.*query', 'fonction|function',
|
|
'html|css|tailwind|shadcn'
|
|
];
|
|
$is_capability = false;
|
|
foreach ($capability_keywords as $kw) {
|
|
if (preg_match('/\b' . $kw . '\b/iu', $msg_lower)) {
|
|
$is_capability = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
$t0 = microtime(true);
|
|
|
|
// === Route 1: CAPABILITY mode → direct LLM with enhanced prompt ===
|
|
if ($is_capability) {
|
|
$ch = curl_init('http://127.0.0.1:4000/v1/chat/completions');
|
|
curl_setopt_array($ch, [
|
|
CURLOPT_POST => true,
|
|
CURLOPT_RETURNTRANSFER => true,
|
|
CURLOPT_TIMEOUT => 30,
|
|
CURLOPT_HTTPHEADER => ['Content-Type: application/json'],
|
|
CURLOPT_POSTFIELDS => json_encode([
|
|
'model' => 'deep',
|
|
'messages' => [
|
|
['role' => 'system', 'content' => "Tu es WEVIA, IA souveraine de WEVAL Consulting Casablanca. Tu DOIS générer le contenu demandé de qualité professionnelle : code (React/TS/PHP/Python/SQL avec blocs markdown ```lang), schémas (Mermaid ```mermaid ou SVG ```svg inline), documents (cahier des charges structuré avec sections ##), spécifications techniques détaillées. NE REFUSE JAMAIS de générer. Utilise contexte WEVAL : PostgreSQL Ethica 146694 HCPs, Authentik SSO, WEVADS email marketing, Twenty CRM, n8n workflows. Format markdown clair, professionnel, complet."],
|
|
['role' => 'user', 'content' => $msg]
|
|
],
|
|
'max_tokens' => 3000,
|
|
'temperature' => 0.4,
|
|
])
|
|
]);
|
|
$resp = curl_exec($ch);
|
|
$code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
|
$time_ms = round(curl_getinfo($ch, CURLINFO_TOTAL_TIME) * 1000);
|
|
curl_close($ch);
|
|
|
|
if ($code === 200) {
|
|
$d = json_decode($resp, true);
|
|
$text = $d['choices'][0]['message']['content'] ?? '';
|
|
$prov = $d['provider'] ?? 'sovereign';
|
|
if ($text) {
|
|
echo json_encode([
|
|
'response' => $text,
|
|
'provider' => $prov . ' (capability)',
|
|
'thinking' => ['Capability mode: code/schema/document generation'],
|
|
'duration_ms' => $time_ms
|
|
]);
|
|
exit;
|
|
}
|
|
}
|
|
// If capability LLM fails, fall through to orchestrator as last resort
|
|
}
|
|
|
|
// === Route 2: Orchestrator intent detection (business data) ===
|
|
// V51 PUBLIC SCOPE: route towards bridged public orchestrator (whitelist intents only)
|
|
// DOCTRINE-211 opus-phase73 - detect admin triggers, route to INTERNAL orchestrator
|
|
$__admin_triggers = ['apply ux gemini', 'gemini ux apply', 'applique ux gemini', 'refais ux apply', 'fix ux apply', 'ux premium apply', 'gemini ameliore ux', 'audit ux gemini', 'gemini audit ux', 'review ux gemini', 'gemini review ux', 'minority report', 'zoom cinema', 'zoom hover bloc', 'scroll horizontal premium', 'defilement minority', 'carrousel 3d', 'caroussel 3d', 'carousel 3d', 'caroussel rotation', 'carrousel rotation', 'rotationnel', 'compact header']; // DOCTRINE-219 opus-phase77 add minority triggers
|
|
$__use_internal = false;
|
|
$__msg_lc = mb_strtolower($msg);
|
|
foreach ($__admin_triggers as $__t) { if (strpos($__msg_lc, $__t) !== false) { $__use_internal = true; break; } }
|
|
$orch_url = $__use_internal
|
|
? 'http://127.0.0.1/api/wevia-sse-orchestrator.php?msg=' . urlencode($msg)
|
|
: 'http://127.0.0.1/api/wevia-sse-orchestrator-public.php?msg=' . urlencode($msg);
|
|
// DOCTRINE-214 opus-phase74 - timeout adapte pour admin triggers (Gemini apply 60s+)
|
|
$__orch_timeout = $__use_internal ? 90 : 12;
|
|
$ch = curl_init($orch_url);
|
|
curl_setopt_array($ch, [
|
|
CURLOPT_RETURNTRANSFER => true,
|
|
CURLOPT_TIMEOUT => $__orch_timeout,
|
|
CURLOPT_CONNECTTIMEOUT => 3,
|
|
CURLOPT_HTTPHEADER => ['Host: weval-consulting.com'],
|
|
]);
|
|
$sse_body = curl_exec($ch);
|
|
$orch_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
|
curl_close($ch);
|
|
|
|
$exec_results = [];
|
|
$llm_synthesis = null;
|
|
|
|
if ($orch_code === 200 && $sse_body) {
|
|
foreach (explode("\n", $sse_body) as $line) {
|
|
if (strpos($line, 'data: ') !== 0) continue;
|
|
$evt = @json_decode(substr($line, 6), true);
|
|
if (!$evt || !isset($evt['type'])) continue;
|
|
if ($evt['type'] === 'exec_result' && !empty($evt['id']) && !empty($evt['result'])) {
|
|
$exec_results[$evt['id']] = substr($evt['result'], 0, 1500);
|
|
} elseif ($evt['type'] === 'exec' && !empty($evt['intent']) && !empty($evt['text'])) {
|
|
// DOCTRINE-212 opus-phase73 - parse internal orchestrator exec events (not just exec_result)
|
|
$exec_results[$evt['intent']] = substr($evt['text'], 0, 1500);
|
|
} elseif ($evt['type'] === 'llm_synthesis' && !empty($evt['text'])) {
|
|
$llm_synthesis = $evt['text'];
|
|
}
|
|
}
|
|
}
|
|
|
|
$orch_ms = round((microtime(true) - $t0) * 1000);
|
|
|
|
// Require at least 1 business intent AND query has business keyword
|
|
$has_business_intent = !empty($exec_results);
|
|
$has_business_keyword = preg_match('/\b(combien|status|etat|nombre|liste|show|afficher|how\s+many|count|apply|gemini|ux|audit|review|refais|applique)\b/iu', $msg_lower); // DOCTRINE-213 opus-phase73 add admin triggers
|
|
|
|
if ($has_business_intent && $has_business_keyword) {
|
|
$combined = "Data WEVIA (intents executes: " . implode(', ', array_keys($exec_results)) . "):\n\n";
|
|
foreach ($exec_results as $id => $out) {
|
|
$combined .= "**{$id}:**\n" . trim($out) . "\n\n";
|
|
}
|
|
if ($llm_synthesis) {
|
|
$combined .= "---\n" . $llm_synthesis;
|
|
}
|
|
echo json_encode([
|
|
'response' => $combined,
|
|
'provider' => 'orchestrator',
|
|
'intents_fired' => array_keys($exec_results),
|
|
'thinking' => ['Orchestrator intents detected + business keyword'],
|
|
'duration_ms' => $orch_ms
|
|
]);
|
|
exit;
|
|
}
|
|
|
|
// === V53 FIX: Honor public orchestrator REFUSAL message ===
|
|
// If orchestrator returned llm_synthesis containing a refusal (blocked topic) → return it
|
|
// DO NOT fall back to LLM (which would hallucinate the blocked topic)
|
|
if ($llm_synthesis && preg_match('/(pas\s+disponible\s+publiquement|information\s+(reservee|confidentielle)|contactez\s+sales@weval|access_restricted|non\s+autoris)/iu', $llm_synthesis)) {
|
|
echo json_encode([
|
|
'response' => $llm_synthesis,
|
|
'provider' => 'orchestrator-public-guard',
|
|
'thinking' => ['Public orchestrator blocked topic — refusal honored (V53)'],
|
|
'duration_ms' => $orch_ms
|
|
]);
|
|
exit;
|
|
}
|
|
|
|
// === Route 3: Fallback sovereign LLM direct ===
|
|
$ch = curl_init('http://127.0.0.1:4000/v1/chat/completions');
|
|
curl_setopt_array($ch, [
|
|
CURLOPT_POST => true,
|
|
CURLOPT_RETURNTRANSFER => true,
|
|
CURLOPT_TIMEOUT => 15,
|
|
CURLOPT_HTTPHEADER => ['Content-Type: application/json'],
|
|
CURLOPT_POSTFIELDS => json_encode([
|
|
'model' => 'auto',
|
|
'messages' => [
|
|
['role' => 'system', 'content' => 'Tu es WEVIA, IA souveraine de WEVAL Consulting Casablanca, cabinet transformation digitale. Reponds en francais, professionnel, concis. CONTEXTE WEVAL (utilise UNIQUEMENT ces faits, NE JAMAIS INVENTER) : (1) Ethica = base B2B pharma WEVAL au Maghreb (Algerie, Maroc, Tunisie) pour campagnes email marketing sante ; (2) WEVADS = plateforme email marketing proprietaire WEVAL ; (3) SAP Ecosystem Partner ; (4) DeerFlow = outil research agent open-source multi-agents WEVAL (PAS marketing automation) ; (5) Paperclip = plateforme WEVAL pour agents IA ; (6) WEVIA = IA souveraine WEVAL ; (7) WEVCODE = assistant code souverain WEVAL ; (8) WEDROID = diagnostic backend WEVAL ; (9) DSH-PREDICT = predictive analytics WEVAL ; (10) WePredict = intelligence competitive WEVAL. Si un terme evoque un produit WEVAL inconnu, refuse poliment plutot que dinventer. Si la question concerne des DONNEES INTERNES precises (HCPs par pays, credentials, warmup accounts, pmta, ethica live details), reponds : \"Cette information est confidentielle. Contactez sales@weval-consulting.com.\" NE JAMAIS inventer de chiffres ou decrire Ethica comme autre chose que la base HCP B2B.'],
|
|
['role' => 'user', 'content' => $msg]
|
|
],
|
|
'max_tokens' => 1500,
|
|
'temperature' => 0.3,
|
|
])
|
|
]);
|
|
$resp = curl_exec($ch);
|
|
$code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
|
$time_ms = round(curl_getinfo($ch, CURLINFO_TOTAL_TIME) * 1000);
|
|
curl_close($ch);
|
|
|
|
if ($code === 200) {
|
|
$d = json_decode($resp, true);
|
|
$text = $d['choices'][0]['message']['content'] ?? '';
|
|
$prov = $d['provider'] ?? 'sovereign';
|
|
if ($text) {
|
|
echo json_encode([
|
|
'response' => $text,
|
|
'provider' => $prov . ' (fallback)',
|
|
'thinking' => ['No intent match, LLM fallback'],
|
|
'duration_ms' => $time_ms,
|
|
'orch_ms' => $orch_ms
|
|
]);
|
|
exit;
|
|
}
|
|
}
|
|
|
|
echo json_encode(['response' => 'Tous les providers sont occupes. Reessayez.', 'provider' => 'busy', 'duration_ms' => $time_ms]);
|