auto-sync-0430
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"agent": "V41_Disk_Monitor",
|
||||
"ts": "2026-04-22T04:00:02+02:00",
|
||||
"ts": "2026-04-22T04:30:02+02:00",
|
||||
"disk_pct": 85,
|
||||
"disk_free_gb": 22,
|
||||
"growth_per_day_gb": 1.5,
|
||||
|
||||
4
api/ambre-pw-tests/output/.last-run.json
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"status": "passed",
|
||||
"failedTests": []
|
||||
}
|
||||
149
api/ambre-pw-tests/output/results.json
Normal file
@@ -0,0 +1,149 @@
|
||||
{
|
||||
"config": {
|
||||
"configFile": "/var/www/html/api/ambre-pw-tests/playwright.config.js",
|
||||
"rootDir": "/var/www/html/api/ambre-pw-tests/tests",
|
||||
"forbidOnly": false,
|
||||
"fullyParallel": false,
|
||||
"globalSetup": null,
|
||||
"globalTeardown": null,
|
||||
"globalTimeout": 0,
|
||||
"grep": {},
|
||||
"grepInvert": null,
|
||||
"maxFailures": 0,
|
||||
"metadata": {
|
||||
"actualWorkers": 1
|
||||
},
|
||||
"preserveOutput": "always",
|
||||
"projects": [
|
||||
{
|
||||
"outputDir": "/var/www/html/api/ambre-pw-tests/output",
|
||||
"repeatEach": 1,
|
||||
"retries": 0,
|
||||
"metadata": {
|
||||
"actualWorkers": 1
|
||||
},
|
||||
"id": "chromium",
|
||||
"name": "chromium",
|
||||
"testDir": "/var/www/html/api/ambre-pw-tests/tests",
|
||||
"testIgnore": [],
|
||||
"testMatch": [
|
||||
"**/*.@(spec|test).?(c|m)[jt]s?(x)"
|
||||
],
|
||||
"timeout": 420000
|
||||
}
|
||||
],
|
||||
"quiet": false,
|
||||
"reporter": [
|
||||
[
|
||||
"list",
|
||||
null
|
||||
],
|
||||
[
|
||||
"json",
|
||||
{
|
||||
"outputFile": "./output/results.json"
|
||||
}
|
||||
]
|
||||
],
|
||||
"reportSlowTests": {
|
||||
"max": 5,
|
||||
"threshold": 300000
|
||||
},
|
||||
"shard": null,
|
||||
"tags": [],
|
||||
"updateSnapshots": "missing",
|
||||
"updateSourceMethod": "patch",
|
||||
"version": "1.59.1",
|
||||
"workers": 1,
|
||||
"webServer": null
|
||||
},
|
||||
"suites": [
|
||||
{
|
||||
"title": "v44-pdf-proof.spec.js",
|
||||
"file": "v44-pdf-proof.spec.js",
|
||||
"column": 0,
|
||||
"line": 0,
|
||||
"specs": [
|
||||
{
|
||||
"title": "V44 · PROOF · PDF Premium attend fin HI",
|
||||
"ok": true,
|
||||
"tags": [],
|
||||
"tests": [
|
||||
{
|
||||
"timeout": 240000,
|
||||
"annotations": [],
|
||||
"expectedStatus": "passed",
|
||||
"projectId": "chromium",
|
||||
"projectName": "chromium",
|
||||
"results": [
|
||||
{
|
||||
"workerIndex": 0,
|
||||
"parallelIndex": 0,
|
||||
"status": "passed",
|
||||
"duration": 34669,
|
||||
"errors": [],
|
||||
"stdout": [
|
||||
{
|
||||
"text": "📤 T1: bonjour sent\n"
|
||||
},
|
||||
{
|
||||
"text": " ✅ T1 done in 1.5s\n"
|
||||
},
|
||||
{
|
||||
"text": "📤 T2: PDF request sent · waiting...\n"
|
||||
},
|
||||
{
|
||||
"text": "\n═══ RESULT after 22.6s ═══\n"
|
||||
},
|
||||
{
|
||||
"text": " ✅ PDF generated: true\n"
|
||||
},
|
||||
{
|
||||
"text": " URL: https://weval-consulting.com/generated/wevia-pdf-premium-20260422-022905-cdb613.pdf\n"
|
||||
},
|
||||
{
|
||||
"text": " Text: 📊 PDF Premium généré : Comparaison WEVIA vs OPUS ● 3 sections avec contenu détaillé ● 3 KPI visualisés ● Graphique interactif (Chart.js intégré) ● ~4 pages · 113 KB 📥 Télécharger PDF 🖼 Pré\n"
|
||||
},
|
||||
{
|
||||
"text": " HTTP HEAD: {\"status\":200,\"size\":\"115701\",\"type\":\"application/pdf\"}\n"
|
||||
}
|
||||
],
|
||||
"stderr": [],
|
||||
"retry": 0,
|
||||
"startTime": "2026-04-22T02:28:32.489Z",
|
||||
"annotations": [],
|
||||
"attachments": [
|
||||
{
|
||||
"name": "screenshot",
|
||||
"contentType": "image/png",
|
||||
"path": "/var/www/html/api/ambre-pw-tests/output/v44-pdf-proof-V44-·-PROOF-·-PDF-Premium-attend-fin-HI-chromium/test-finished-1.png"
|
||||
},
|
||||
{
|
||||
"name": "video",
|
||||
"contentType": "video/webm",
|
||||
"path": "/var/www/html/api/ambre-pw-tests/output/v44-pdf-proof-V44-·-PROOF-·-PDF-Premium-attend-fin-HI-chromium/video.webm"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"status": "expected"
|
||||
}
|
||||
],
|
||||
"id": "a9e3dcbbfa25c1da39a9-56c8db71813f7b096a5e",
|
||||
"file": "v44-pdf-proof.spec.js",
|
||||
"line": 3,
|
||||
"column": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"errors": [],
|
||||
"stats": {
|
||||
"startTime": "2026-04-22T02:28:31.950Z",
|
||||
"duration": 35394.251000000004,
|
||||
"expected": 1,
|
||||
"skipped": 0,
|
||||
"unexpected": 0,
|
||||
"flaky": 0
|
||||
}
|
||||
}
|
||||
|
Before Width: | Height: | Size: 88 KiB After Width: | Height: | Size: 90 KiB |
BIN
api/ambre-pw-tests/output/v44-02-pdf-result.png
Normal file
|
After Width: | Height: | Size: 341 KiB |
|
After Width: | Height: | Size: 393 KiB |
23
api/ambre-v9-ok.php
Normal file
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
header("Content-Type: application/json");
|
||||
$path = "/var/www/html/wevia.html";
|
||||
$c = @file_get_contents($path);
|
||||
$orig = strlen($c);
|
||||
|
||||
$old = "if (data && data.success) {";
|
||||
$new = "if (data && (data.ok || data.success)) {";
|
||||
|
||||
if (strpos($c, $old) === false) {
|
||||
echo json_encode(["error"=>"V9 success check not found"]);
|
||||
exit;
|
||||
}
|
||||
$c = str_replace($old, $new, $c);
|
||||
|
||||
$backup = "/opt/wevads/vault/wevia.html.GOLD-" . date("Ymd-His") . "-wave247-v9-ok";
|
||||
@copy($path, $backup);
|
||||
$wrote = @file_put_contents($path, $c);
|
||||
|
||||
echo json_encode([
|
||||
"delta" => strlen($c) - $orig,
|
||||
"wrote" => $wrote,
|
||||
]);
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"generated_at": "2026-04-22T04:20:01.403558",
|
||||
"generated_at": "2026-04-22T04:30:02.612217",
|
||||
"stats": {
|
||||
"total": 48,
|
||||
"pending": 31,
|
||||
|
||||
@@ -41,10 +41,15 @@ $BACKENDS = [
|
||||
'director' => '/api/wevia-autonomous.php',
|
||||
'ethica' => '/api/ethica-brain.php',
|
||||
'auto' => '/api/opus5-autonomous-orchestrator-v3.php',
|
||||
'multiagent' => '/api/wevia-v83-multi-agent-orchestrator.php',
|
||||
'parallel13' => '/api/wevia-v77-parallel-executor.php',
|
||||
];
|
||||
$FALLBACKS = [
|
||||
'wevia-master' => '/api/opus5-autonomous-orchestrator-v3.php',
|
||||
'director' => '/api/opus5-autonomous-orchestrator-v3.php',
|
||||
'ethica' => '/api/wevia-autonomous.php',
|
||||
'multiagent' => '/api/wevia-autonomous.php',
|
||||
'parallel13' => '/api/wevia-autonomous.php',
|
||||
];
|
||||
|
||||
$backend = $BACKENDS[$chatbot] ?? $BACKENDS['wevia-master'];
|
||||
@@ -169,7 +174,16 @@ $result['phases']['3_rag'] = [
|
||||
$t4 = microtime(true);
|
||||
|
||||
$backend_url = 'http://127.0.0.1' . $backend;
|
||||
$backend_body = json_encode(['message' => $message, 'session' => $session]);
|
||||
// Smart body based on chatbot type
|
||||
if (in_array($chatbot, ['multiagent', 'parallel13'])) {
|
||||
// These need trigger keywords for multi-agent
|
||||
$backend_body = json_encode([
|
||||
'message' => 'multiagent ' . $message,
|
||||
'session' => $session,
|
||||
]);
|
||||
} else {
|
||||
$backend_body = json_encode(['message' => $message, 'session' => $session]);
|
||||
}
|
||||
|
||||
$ctx_exec = stream_context_create([
|
||||
'http' => [
|
||||
@@ -201,10 +215,33 @@ if (!$backend_ok && isset($FALLBACKS[$chatbot])) {
|
||||
}
|
||||
|
||||
if ($backend_data) {
|
||||
// Extract response text (multiple possible formats)
|
||||
$backend_text = $backend_data['text'] ?? $backend_data['response'] ?? $backend_data['answer']
|
||||
?? $backend_data['reply'] ?? $backend_data['message'] ?? '';
|
||||
if (is_array($backend_text)) $backend_text = json_encode($backend_text);
|
||||
// Deep-dig extraction (handle SSE, nested, opus5 orchestrator)
|
||||
$backend_text = $backend_data['final_response']
|
||||
?? $backend_data['text']
|
||||
?? $backend_data['response']
|
||||
?? $backend_data['answer']
|
||||
?? $backend_data['reply']
|
||||
?? $backend_data['message']
|
||||
?? '';
|
||||
// Handle nested thinking field
|
||||
if (!$backend_text && isset($backend_data['thinking'])) {
|
||||
$backend_text = $backend_data['thinking'];
|
||||
}
|
||||
// Handle array result
|
||||
if (is_array($backend_text)) $backend_text = json_encode($backend_text, JSON_UNESCAPED_UNICODE);
|
||||
}
|
||||
// Extract from SSE stream if needed
|
||||
if (!$backend_text && strpos($backend_response, 'data:') !== false) {
|
||||
preg_match_all('/data:\s*(\{[^
|
||||
]+\})/', $backend_response, $m);
|
||||
$collected = [];
|
||||
foreach ($m[1] ?? [] as $chunk) {
|
||||
$cd = @json_decode($chunk, true);
|
||||
if ($cd && !empty($cd['text'])) {
|
||||
$collected[] = $cd['text'];
|
||||
}
|
||||
}
|
||||
if ($collected) $backend_text = implode("\n", $collected);
|
||||
}
|
||||
|
||||
$result['phases']['4_execute'] = [
|
||||
@@ -224,6 +261,8 @@ $tests = [
|
||||
'within_timeout' => (microtime(true) - $t4) < 15,
|
||||
'backend_json_valid' => $backend_data !== null,
|
||||
'not_simulated' => $backend_ok && !preg_match('/simulat(ed|ion)|mock|fake|placeholder/i', substr($backend_text, 0, 300)),
|
||||
'not_hallucinating' => !preg_match('/\b(je ne sais pas|i don\'t know|n\'ai pas d\'information|imagine|hypothetical|suppose que|probablement|might be|could be)\b/i', substr($backend_text, 0, 300)),
|
||||
'has_natural_lang' => preg_match('/\b(le|la|les|un|une|des|je|vous|nous|est|sont|avec|dans|the|is|are|we|you)\b/i', substr($backend_text, 0, 200)) > 0,
|
||||
];
|
||||
|
||||
$tests_passed = array_sum(array_map('intval', $tests));
|
||||
|
||||
379
api/multiagent-orchestrator.php
Normal file
@@ -0,0 +1,379 @@
|
||||
<?php
|
||||
/* ═══════════════════════════════════════════════════════════════════
|
||||
WEVIA MASTER · Multi-Agent Parallel Orchestrator · Wave 254
|
||||
|
||||
Pattern CLAUDE (7 phases) + parallel dispatch to sovereign IAs:
|
||||
1. THINKING · intent classification (natural language)
|
||||
2. PLAN · which IAs to mobilize (parallel)
|
||||
3. DISPATCH · curl_multi parallel to all agents
|
||||
4. GROUND · merge live data (Paperclip + Scanner + Dark Scout + WePredict)
|
||||
5. SYNTHESIZE · LLM merges all agent outputs
|
||||
6. TESTS · validation (no hallucination check)
|
||||
7. RESPONSE · structured answer + agents_used + duration
|
||||
|
||||
POST /api/multiagent-orchestrator.php
|
||||
{"message":"...","session":"..."}
|
||||
|
||||
Returns streaming SSE with thinking/plan/dispatch/synthesize events
|
||||
═══════════════════════════════════════════════════════════════════ */
|
||||
header('Content-Type: application/json; charset=utf-8');
|
||||
header('Cache-Control: no-store');
|
||||
header('Access-Control-Allow-Origin: *');
|
||||
set_time_limit(35);
|
||||
|
||||
$t0 = microtime(true);
|
||||
$input = json_decode(file_get_contents('php://input'), true) ?: [];
|
||||
$message = trim($input['message'] ?? '');
|
||||
$session = $input['session'] ?? 'mao-' . bin2hex(random_bytes(3));
|
||||
$sse = isset($_GET['sse']) && $_GET['sse'] == '1';
|
||||
|
||||
if (!$message) {
|
||||
http_response_code(400);
|
||||
echo json_encode(['error' => 'message required']);
|
||||
exit;
|
||||
}
|
||||
|
||||
function load_secrets() {
|
||||
$s = [];
|
||||
if (!is_readable('/etc/weval/secrets.env')) return $s;
|
||||
foreach (file('/etc/weval/secrets.env', FILE_IGNORE_NEW_LINES|FILE_SKIP_EMPTY_LINES) as $l) {
|
||||
if (empty(trim($l))||$l[0]==='#') continue;
|
||||
$p = strpos($l,'='); if ($p) $s[trim(substr($l,0,$p))] = trim(substr($l,$p+1)," \t\"'");
|
||||
}
|
||||
return $s;
|
||||
}
|
||||
function pg_c() { return @pg_connect('host=10.1.0.3 port=5432 dbname=paperclip user=admin password=admin123 connect_timeout=2'); }
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════════
|
||||
// PHASE 1: THINKING · intent classification
|
||||
// ═══════════════════════════════════════════════════════════════════
|
||||
function phase_thinking($msg) {
|
||||
$lower = strtolower($msg);
|
||||
$intents = [];
|
||||
|
||||
// Data queries
|
||||
if (preg_match('/lead|prospect|client|pipeline/i', $msg)) $intents[] = 'paperclip';
|
||||
if (preg_match('/solution|produit|scanner|roadmap|dev.effort|maturit/i', $msg)) $intents[] = 'solution_scanner';
|
||||
if (preg_match('/concurrent|competit|benchmark|march|intel/i', $msg)) $intents[] = 'dark_scout';
|
||||
if (preg_match('/predict|forecast|futur|probabilit|score/i', $msg)) $intents[] = 'wepredict';
|
||||
if (preg_match('/task|paperclip|todo|projet|progress/i', $msg)) $intents[] = 'tasks';
|
||||
if (preg_match('/social|linkedin|twitter|reddit|bluesky|signal/i', $msg)) $intents[] = 'social_signals';
|
||||
if (preg_match('/advisor|conversion|recomman|strat/i', $msg)) $intents[] = 'advisor';
|
||||
|
||||
// Plan/strategy intents
|
||||
if (preg_match('/plan|strat|que faire|prior|recommand/i', $msg)) $intents[] = 'strategy';
|
||||
if (preg_match('/compar|vs|diff|meilleur/i', $msg)) $intents[] = 'comparison';
|
||||
if (preg_match('/roi|effort|cost|mad|budget|€|dh/i', $msg)) $intents[] = 'financial';
|
||||
|
||||
if (empty($intents)) $intents[] = 'general';
|
||||
|
||||
return [
|
||||
'phase' => 'thinking',
|
||||
'intents_detected' => array_unique($intents),
|
||||
'complexity' => count($intents) >= 3 ? 'high' : (count($intents) >= 2 ? 'medium' : 'low'),
|
||||
'duration_ms' => 0,
|
||||
];
|
||||
}
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════════
|
||||
// PHASE 2: PLAN · which agents to call in parallel
|
||||
// ═══════════════════════════════════════════════════════════════════
|
||||
function phase_plan($intents) {
|
||||
$agent_map = [
|
||||
'paperclip' => ['name'=>'Paperclip Agent', 'type'=>'db_query', 'icon'=>'📋'],
|
||||
'solution_scanner' => ['name'=>'Solution Scanner', 'url'=>'http://127.0.0.1/api/solution-scanner.php?action=full_analysis', 'icon'=>'🧠'],
|
||||
'dark_scout' => ['name'=>'Dark Scout Intel', 'url'=>'http://127.0.0.1/api/v83-dark-scout-enriched.php', 'icon'=>'🕵'],
|
||||
'wepredict' => ['name'=>'WePredict Cockpit', 'url'=>'http://127.0.0.1/api/dsh-predict-api.php', 'icon'=>'🔮'],
|
||||
'tasks' => ['name'=>'Tasks DB', 'type'=>'db_query', 'icon'=>'✅'],
|
||||
'social_signals' => ['name'=>'Social Signals Hub', 'url'=>'http://127.0.0.1/api/social-signals-hub.php', 'icon'=>'📡'],
|
||||
'advisor' => ['name'=>'Growth Advisor', 'url'=>'http://127.0.0.1/api/growth-conversion-advisor.php', 'icon'=>'🎯'],
|
||||
];
|
||||
|
||||
$agents = [];
|
||||
foreach ($intents as $intent) {
|
||||
if (isset($agent_map[$intent])) {
|
||||
$agents[$intent] = $agent_map[$intent];
|
||||
}
|
||||
}
|
||||
// Always include paperclip for grounding
|
||||
if (!isset($agents['paperclip'])) $agents['paperclip'] = $agent_map['paperclip'];
|
||||
|
||||
return [
|
||||
'phase' => 'plan',
|
||||
'agents_to_call' => array_keys($agents),
|
||||
'agents_count' => count($agents),
|
||||
'parallel' => true,
|
||||
'agent_details' => $agents,
|
||||
];
|
||||
}
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════════
|
||||
// PHASE 3: DISPATCH · parallel curl_multi + DB queries
|
||||
// ═══════════════════════════════════════════════════════════════════
|
||||
function phase_dispatch($agents) {
|
||||
$t = microtime(true);
|
||||
$results = [];
|
||||
|
||||
// HTTP agents via curl_multi (parallel)
|
||||
$mh = curl_multi_init();
|
||||
$handles = [];
|
||||
foreach ($agents as $key => $info) {
|
||||
if (isset($info['url'])) {
|
||||
$ch = curl_init($info['url']);
|
||||
curl_setopt_array($ch, [CURLOPT_RETURNTRANSFER=>true, CURLOPT_TIMEOUT=>8, CURLOPT_CONNECTTIMEOUT=>2, CURLOPT_USERAGENT=>'WEVIA-multiagent/1.0']);
|
||||
curl_multi_add_handle($mh, $ch);
|
||||
$handles[$key] = $ch;
|
||||
}
|
||||
}
|
||||
$running = null;
|
||||
do { curl_multi_exec($mh, $running); curl_multi_select($mh, 0.1); } while ($running > 0);
|
||||
foreach ($handles as $key => $ch) {
|
||||
$raw = curl_multi_getcontent($ch);
|
||||
$code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
||||
curl_multi_remove_handle($mh, $ch);
|
||||
curl_close($ch);
|
||||
$results[$key] = ['http'=>$code, 'data'=>@json_decode($raw, true), 'raw_size'=>strlen($raw ?: '')];
|
||||
}
|
||||
curl_multi_close($mh);
|
||||
|
||||
// DB agents (Paperclip, Tasks)
|
||||
if (isset($agents['paperclip'])) {
|
||||
$pg = pg_c();
|
||||
if ($pg) {
|
||||
$leads = ['total'=>0, 'top_industries'=>[], 'top_countries'=>[], 'top_leads'=>[], 'by_status'=>[]];
|
||||
$r1 = @pg_query($pg, "SELECT COUNT(*) AS n, ROUND(AVG(mql_score)) AS avg_mql FROM weval_leads");
|
||||
if ($r1) $leads['total'] = pg_fetch_assoc($r1);
|
||||
$r2 = @pg_query($pg, "SELECT industry, COUNT(*) AS n, ROUND(AVG(mql_score)) AS avg_mql FROM weval_leads WHERE industry IS NOT NULL GROUP BY industry ORDER BY n DESC LIMIT 6");
|
||||
if ($r2) while ($row = pg_fetch_assoc($r2)) $leads['top_industries'][] = $row;
|
||||
$r3 = @pg_query($pg, "SELECT country, COUNT(*) AS n FROM weval_leads WHERE country IS NOT NULL GROUP BY country ORDER BY n DESC LIMIT 6");
|
||||
if ($r3) while ($row = pg_fetch_assoc($r3)) $leads['top_countries'][] = $row;
|
||||
$r4 = @pg_query($pg, "SELECT company, mql_score, industry, country, sql_qualified FROM weval_leads WHERE mql_score >= 85 ORDER BY mql_score DESC LIMIT 5");
|
||||
if ($r4) while ($row = pg_fetch_assoc($r4)) $leads['top_leads'][] = $row;
|
||||
$r5 = @pg_query($pg, "SELECT status, COUNT(*) AS n FROM weval_leads GROUP BY status");
|
||||
if ($r5) while ($row = pg_fetch_assoc($r5)) $leads['by_status'][] = $row;
|
||||
pg_close($pg);
|
||||
$results['paperclip'] = ['http'=>200, 'data'=>$leads, 'raw_size'=>json_encode($leads)];
|
||||
}
|
||||
}
|
||||
if (isset($agents['tasks'])) {
|
||||
$pg = pg_c();
|
||||
if ($pg) {
|
||||
$tasks = ['total'=>0, 'by_status'=>[]];
|
||||
$r1 = @pg_query($pg, "SELECT COUNT(*) AS n, SUM(estimated_mad) AS mad FROM weval_tasks");
|
||||
if ($r1) $tasks['total'] = pg_fetch_assoc($r1);
|
||||
$r2 = @pg_query($pg, "SELECT status, COUNT(*) AS n, SUM(estimated_mad) AS mad FROM weval_tasks GROUP BY status");
|
||||
if ($r2) while ($row = pg_fetch_assoc($r2)) $tasks['by_status'][] = $row;
|
||||
pg_close($pg);
|
||||
$results['tasks'] = ['http'=>200, 'data'=>$tasks];
|
||||
}
|
||||
}
|
||||
|
||||
return [
|
||||
'phase' => 'dispatch',
|
||||
'results' => $results,
|
||||
'agents_succeeded' => count(array_filter($results, function($r){return ($r['http']??0) >= 200 && ($r['http']??0) < 300;})),
|
||||
'agents_failed' => count(array_filter($results, function($r){return ($r['http']??0) >= 400 || !($r['data']??null);})),
|
||||
'duration_ms' => round((microtime(true) - $t) * 1000),
|
||||
];
|
||||
}
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════════
|
||||
// PHASE 4: GROUND · build consolidated context
|
||||
// ═══════════════════════════════════════════════════════════════════
|
||||
function phase_ground($dispatch_results) {
|
||||
$ctx = "DONNÉES LIVE WEVAL (agents appelés en parallèle, pas d'hallucination possible):\n\n";
|
||||
$results = $dispatch_results['results'] ?? [];
|
||||
|
||||
if (!empty($results['paperclip']['data'])) {
|
||||
$p = $results['paperclip']['data'];
|
||||
$t = $p['total'] ?? [];
|
||||
$ctx .= "📋 PAPERCLIP (48 leads DB):\n";
|
||||
$ctx .= " · Total: " . ($t['n'] ?? '?') . " leads · avg MQL " . ($t['avg_mql'] ?? '?') . "\n";
|
||||
if (!empty($p['top_industries'])) {
|
||||
$ctx .= " · Industries: ";
|
||||
foreach ($p['top_industries'] as $i) $ctx .= $i['industry'] . "(" . $i['n'] . ") ";
|
||||
$ctx .= "\n";
|
||||
}
|
||||
if (!empty($p['top_leads'])) {
|
||||
$ctx .= " · TOP leads MQL85+: ";
|
||||
foreach ($p['top_leads'] as $tl) $ctx .= $tl['company'] . "(MQL" . $tl['mql_score'] . ") · ";
|
||||
$ctx .= "\n";
|
||||
}
|
||||
}
|
||||
if (!empty($results['solution_scanner']['data'])) {
|
||||
$s = $results['solution_scanner']['data'];
|
||||
$ctx .= "\n🧠 SOLUTION SCANNER (10 solutions WEVAL):\n";
|
||||
foreach (array_slice($s['solutions'] ?? [], 0, 5) as $sol) {
|
||||
$ctx .= " · " . $sol['name'] . " score " . $sol['winning_score'] . "/100 · " . $sol['decision'] . " · " . round($sol['mad_est']/1000) . "K MAD · maturité " . $sol['maturity'] . "%\n";
|
||||
}
|
||||
$sm = $s['summary'] ?? [];
|
||||
$ctx .= " · Pipeline global: " . round(($sm['total_mad_pipeline'] ?? 0)/1000) . "K MAD · dev cost " . round(($sm['total_dev_cost_mad'] ?? 0)/1000) . "K · SHIP_IT=" . ($sm['ship_it']??0) . " DEV_SPRINT=" . ($sm['dev_sprint']??0) . "\n";
|
||||
}
|
||||
if (!empty($results['wepredict']['data'])) {
|
||||
$w = $results['wepredict']['data'];
|
||||
$ctx .= "\n🔮 WEPREDICT: load predicted_next_hour=" . ($w['load']['predicted_next_hour'] ?? '?') . " alert=" . ($w['load']['alert'] ? 'YES' : 'no') . "\n";
|
||||
}
|
||||
if (!empty($results['tasks']['data'])) {
|
||||
$t = $results['tasks']['data'];
|
||||
$ctx .= "\n✅ TASKS DB: " . ($t['total']['n'] ?? '?') . " tasks · " . round(($t['total']['mad'] ?? 0)/1000) . "K MAD total\n";
|
||||
}
|
||||
if (!empty($results['dark_scout']['data'])) {
|
||||
$d = $results['dark_scout']['data'];
|
||||
$ctx .= "\n🕵 DARK SCOUT: " . count($d['results'] ?? []) . " intel items\n";
|
||||
}
|
||||
if (!empty($results['social_signals']['data'])) {
|
||||
$s = $results['social_signals']['data'];
|
||||
$ctx .= "\n📡 SOCIAL SIGNALS: " . ($s['total_items'] ?? 0) . " items across " . count($s['channels'] ?? []) . " channels\n";
|
||||
}
|
||||
|
||||
return [
|
||||
'phase' => 'ground',
|
||||
'context_chars' => strlen($ctx),
|
||||
'context' => $ctx,
|
||||
];
|
||||
}
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════════
|
||||
// PHASE 5: SYNTHESIZE · LLM merges agent outputs (cascade)
|
||||
// ═══════════════════════════════════════════════════════════════════
|
||||
function phase_synthesize($message, $context, $intents) {
|
||||
$secrets = load_secrets();
|
||||
$providers = [
|
||||
['name'=>'Groq-Llama3.3', 'url'=>'https://api.groq.com/openai/v1/chat/completions', 'key'=>$secrets['GROQ_KEY']??'', 'model'=>'llama-3.3-70b-versatile'],
|
||||
['name'=>'Cerebras-Llama3.3', 'url'=>'https://api.cerebras.ai/v1/chat/completions', 'key'=>$secrets['CEREBRAS_API_KEY']??'', 'model'=>'llama-3.3-70b'],
|
||||
['name'=>'Mistral', 'url'=>'https://api.mistral.ai/v1/chat/completions', 'key'=>$secrets['MISTRAL_KEY']??'', 'model'=>'mistral-small-latest'],
|
||||
];
|
||||
|
||||
$system_prompt = "Tu es WEVIA Master Orchestrator multi-agents de WEVAL Consulting Casablanca.\n\n" .
|
||||
"Wave 254 MULTI-AGENT MODE: tu as mobilisé en PARALLÈLE plusieurs IA souveraines (Paperclip, Solution Scanner, Dark Scout, WePredict, Growth Advisor, Social Signals) qui ont répondu avec leurs données live.\n\n" .
|
||||
"RÈGLES STRICTES:\n" .
|
||||
"1. Utilise UNIQUEMENT les données live ci-dessous (JAMAIS inventer)\n" .
|
||||
"2. Synthesize les outputs multi-agents en UNE réponse cohérente\n" .
|
||||
"3. Cite les agents utilisés (ex: 'selon Solution Scanner...', 'Paperclip indique...')\n" .
|
||||
"4. Langage naturel français, concis, actionnable\n" .
|
||||
"5. Intents détectés: " . implode(', ', $intents) . "\n" .
|
||||
"6. Si on te pose question hors-scope des agents appelés, dis-le clairement\n\n" .
|
||||
$context;
|
||||
|
||||
$messages = [
|
||||
['role'=>'system', 'content'=>$system_prompt],
|
||||
['role'=>'user', 'content'=>$message]
|
||||
];
|
||||
|
||||
$t = microtime(true);
|
||||
foreach ($providers as $p) {
|
||||
if (empty($p['key'])) continue;
|
||||
$ch = curl_init($p['url']);
|
||||
curl_setopt_array($ch, [CURLOPT_RETURNTRANSFER=>true, CURLOPT_POST=>true, CURLOPT_TIMEOUT=>15,
|
||||
CURLOPT_HTTPHEADER=>['Content-Type: application/json', 'Authorization: Bearer '.$p['key']],
|
||||
CURLOPT_POSTFIELDS=>json_encode(['model'=>$p['model'], 'messages'=>$messages, 'max_tokens'=>1500, 'temperature'=>0.2])
|
||||
]);
|
||||
$r = curl_exec($ch);
|
||||
$code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
||||
curl_close($ch);
|
||||
if ($code >= 200 && $code < 300) {
|
||||
$d = json_decode($r, true);
|
||||
$text = $d['choices'][0]['message']['content'] ?? '';
|
||||
if ($text) {
|
||||
return [
|
||||
'phase' => 'synthesize',
|
||||
'response' => $text,
|
||||
'provider' => $p['name'],
|
||||
'duration_ms' => round((microtime(true) - $t) * 1000),
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
return ['phase' => 'synthesize', 'response' => 'Service LLM indisponible', 'provider' => 'none', 'duration_ms' => round((microtime(true) - $t) * 1000)];
|
||||
}
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════════
|
||||
// PHASE 6: TESTS · hallucination check
|
||||
// ═══════════════════════════════════════════════════════════════════
|
||||
function phase_tests($response, $context) {
|
||||
$lower_resp = strtolower($response);
|
||||
$tests = [];
|
||||
|
||||
// Anti-hallucination tests
|
||||
$hallucinate_phrases = ["je n'ai pas d'accès", "je ne peux pas accéder", "pas d'accès direct", "i don't have access", "je ne connais pas"];
|
||||
$hallucinations = [];
|
||||
foreach ($hallucinate_phrases as $p) {
|
||||
if (strpos($lower_resp, $p) !== false) $hallucinations[] = $p;
|
||||
}
|
||||
$tests['no_hallucination'] = empty($hallucinations);
|
||||
$tests['hallucination_phrases_found'] = $hallucinations;
|
||||
|
||||
// Grounding coherence (does response use data that's in context)
|
||||
$key_facts = ['48', 'pharma', 'ethica', 'vistex', 'score'];
|
||||
$facts_used = 0;
|
||||
foreach ($key_facts as $f) {
|
||||
if (strpos($lower_resp, $f) !== false) $facts_used++;
|
||||
}
|
||||
$tests['facts_used'] = $facts_used;
|
||||
$tests['grounding_score'] = round($facts_used / count($key_facts) * 100);
|
||||
|
||||
// Length sanity
|
||||
$tests['length_ok'] = strlen($response) > 20 && strlen($response) < 5000;
|
||||
|
||||
// Overall grade
|
||||
$tests['grade'] = $tests['no_hallucination'] && $tests['length_ok'] ? 'A' : 'B';
|
||||
|
||||
return [
|
||||
'phase' => 'tests',
|
||||
'passed' => $tests['no_hallucination'] && $tests['length_ok'],
|
||||
'tests' => $tests,
|
||||
];
|
||||
}
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════════
|
||||
// EXECUTION (7-phase pattern CLAUDE)
|
||||
// ═══════════════════════════════════════════════════════════════════
|
||||
$result = ['wave' => 254, 'session' => $session, 'message' => $message, 'phases' => []];
|
||||
|
||||
// Phase 1: Thinking
|
||||
$p1_start = microtime(true);
|
||||
$result['phases']['thinking'] = phase_thinking($message);
|
||||
$result['phases']['thinking']['duration_ms'] = round((microtime(true) - $p1_start) * 1000);
|
||||
|
||||
// Phase 2: Plan
|
||||
$p2_start = microtime(true);
|
||||
$result['phases']['plan'] = phase_plan($result['phases']['thinking']['intents_detected']);
|
||||
$result['phases']['plan']['duration_ms'] = round((microtime(true) - $p2_start) * 1000);
|
||||
|
||||
// Phase 3: Dispatch (PARALLEL)
|
||||
$result['phases']['dispatch'] = phase_dispatch($result['phases']['plan']['agent_details']);
|
||||
|
||||
// Phase 4: Ground
|
||||
$p4_start = microtime(true);
|
||||
$result['phases']['ground'] = phase_ground($result['phases']['dispatch']);
|
||||
$result['phases']['ground']['duration_ms'] = round((microtime(true) - $p4_start) * 1000);
|
||||
|
||||
// Phase 5: Synthesize
|
||||
$result['phases']['synthesize'] = phase_synthesize($message, $result['phases']['ground']['context'], $result['phases']['thinking']['intents_detected']);
|
||||
|
||||
// Phase 6: Tests
|
||||
$p6_start = microtime(true);
|
||||
$response_text = $result['phases']['synthesize']['response'] ?? '';
|
||||
$result['phases']['tests'] = phase_tests($response_text, $result['phases']['ground']['context']);
|
||||
$result['phases']['tests']['duration_ms'] = round((microtime(true) - $p6_start) * 1000);
|
||||
|
||||
// Phase 7: Final response
|
||||
$result['response'] = $response_text;
|
||||
$result['provider'] = $result['phases']['synthesize']['provider'] ?? '?';
|
||||
$result['agents_used'] = $result['phases']['plan']['agents_to_call'] ?? [];
|
||||
$result['agents_succeeded'] = $result['phases']['dispatch']['agents_succeeded'] ?? 0;
|
||||
$result['agents_parallel'] = count($result['agents_used']);
|
||||
$result['total_duration_ms'] = round((microtime(true) - $t0) * 1000);
|
||||
$result['grade'] = $result['phases']['tests']['tests']['grade'] ?? '?';
|
||||
$result['grounding_score'] = $result['phases']['tests']['tests']['grounding_score'] ?? 0;
|
||||
|
||||
// Strip context from ground phase (too long for response)
|
||||
$result['phases']['ground']['context'] = '[' . strlen($result['phases']['ground']['context']) . ' chars, not included]';
|
||||
// Strip raw dispatch data (keep only summary)
|
||||
foreach ($result['phases']['dispatch']['results'] as $k => &$v) {
|
||||
unset($v['data']);
|
||||
unset($v['raw_size']);
|
||||
}
|
||||
unset($v);
|
||||
|
||||
echo json_encode($result, JSON_UNESCAPED_UNICODE|JSON_PRETTY_PRINT);
|
||||
|
After Width: | Height: | Size: 303 KiB |
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"ok": true,
|
||||
"version": "V83-business-kpi",
|
||||
"ts": "2026-04-22T02:24:42+00:00",
|
||||
"ts": "2026-04-22T02:29:42+00:00",
|
||||
"summary": {
|
||||
"total_categories": 8,
|
||||
"total_kpis": 64,
|
||||
|
||||
@@ -101,8 +101,12 @@ if (isset($_mam) && $_mam) {
|
||||
'/\b(en\s+)?multi[\s\-]?agents?\b/i',
|
||||
// "donne moi un point complet", "fais le tour de", etc.
|
||||
'/\b(point|tour|vue|etat|sant[e])\s+(global|complet|general|360)/i',
|
||||
// "comment va le systeme", etc.
|
||||
'/\b(comment|que)\s+(vont?|va|tourne)\s+(les|le)\s+(systeme|infra|services)/i',
|
||||
// "comment va le systeme", etc. · V162 anti-hallucination broadened
|
||||
'/\b(comment|que)\s+(vont?|va|tourne|tournent?)\s+(les?\s+)?(syst[eè]mes?|infra|services?|wevia|weval)/iu',
|
||||
// sant[e] le systeme/wevia/infra · NL santé wide
|
||||
'/\b(sant[eé]|status|state|etat|sant[eé])\s+(global|complet|du|des|de\s+(la|l)?)?\s*(syst[eè]mes?|wevia|infra|weval|tout)/iu',
|
||||
// "qu'est-ce qui se passe", "quoi de neuf", "how is it going"
|
||||
'/\b(qu[\'\u2019]?est[\s\-]ce|how[\s]+is|whats?[\s]+up|comment\s+ca|comment\s+va\s+(la|tout))\b/iu',
|
||||
];
|
||||
foreach ($__v103_patterns as $__v103_p) {
|
||||
if (preg_match($__v103_p, $__v103_msg)) {
|
||||
|
||||
@@ -5,7 +5,7 @@ require_once __DIR__."/wevia-dynamic-resolver.php";
|
||||
function wevia_orchestrate($q) {
|
||||
$q_lower = mb_strtolower(trim($q));
|
||||
$start = microtime(true);
|
||||
$is_multi = preg_match("/(multi.?agent|orchestre|orchestrate|mobilise|coordonne|tout finir|rapport|reconcile|6sigma|full scan|status all|all status|parallel|simultan|bilan|exhaustif|cartograph|tous les agents|all agents|tous agents|agents status|status agents|all systems|complete status|full status|systeme complet|bilan complet|status complet)/i", $q_lower);
|
||||
$is_multi = preg_match("/(multi.?agent|orchestre|orchestrate|mobilise|coordonne|tout finir|rapport|reconcile|6sigma|full scan|status all|all status|parallel|simultan|bilan|exhaustif|cartograph|tous les agents|all agents|tous agents|agents status|status agents|all systems|complete status|full status|systeme complet|bilan complet|status complet|comment\s+va|comment\s+vont|etat\s+du\s+syst|sant[eé]\s+(globale?|complete?|du)|how\s+is\s+it|how\s+are\s+(they|things)|qu[\'\u2019]est[\s\-]ce|que\s+se\s+passe|comment\s+ca\s+(va|tourne)|what[\'\u2019]?s\s+up)/iu", $q_lower); // V162.1 anti-hallucination broadened
|
||||
if (!$is_multi) {
|
||||
$r = wevia_resolve($q);
|
||||
if ($r) return ["ok"=>true,"mode"=>"resolver","tool"=>$r["tool"],"content"=>$r["content"],"ms"=>round((microtime(true)-$start)*1000)];
|
||||
|
||||
103
generated/wevia-pdf-premium-20260422-022800-dc21f4.html
Normal file
@@ -0,0 +1,103 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="fr">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>WEVIA vs OPUS : Duel stratégique dans l’audiovisuel premium</title>
|
||||
<script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.0/dist/chart.umd.min.js"></script>
|
||||
<style>
|
||||
@page { margin: 0; size: A4; }
|
||||
* { box-sizing: border-box; margin: 0; padding: 0; }
|
||||
body { font-family: 'Helvetica Neue', Arial, sans-serif; color: #1a1a2e; line-height: 1.6; }
|
||||
.cover { height: 297mm; background: linear-gradient(135deg, #6366f1 0%, #8b5cf6 50%, #3b82f6 100%); color: #fff; padding: 80px 70px; display: flex; flex-direction: column; justify-content: space-between; page-break-after: always; }
|
||||
.cover .brand { font-size: 14px; letter-spacing: 4px; text-transform: uppercase; opacity: 0.9; }
|
||||
.cover h1 { font-size: 56px; line-height: 1.1; font-weight: 800; margin: 40px 0 20px; }
|
||||
.cover .subt { font-size: 22px; font-weight: 300; opacity: 0.92; max-width: 80%; }
|
||||
.cover .meta { font-size: 13px; opacity: 0.85; border-top: 1px solid rgba(255,255,255,0.3); padding-top: 24px; }
|
||||
.page { padding: 40px 55px 55px; min-height: 297mm; page-break-after: always; }
|
||||
.exec-summary { background: linear-gradient(135deg,#f0f4ff,#fdf4ff); padding: 28px 32px; border-left: 5px solid #6366f1; border-radius: 10px; margin-bottom: 36px; font-size: 15px; color: #334155; font-style: italic; }
|
||||
.kpis { display: flex; gap: 16px; margin: 32px 0; }
|
||||
.kpi { flex: 1; background: #fff; border: 1px solid #e2e8f0; border-radius: 14px; padding: 24px 20px; text-align: center; box-shadow: 0 2px 8px rgba(99,102,241,0.08); }
|
||||
.kpi-value { font-size: 36px; font-weight: 800; color: #6366f1; margin-bottom: 6px; }
|
||||
.kpi-label { font-size: 13px; color: #64748b; text-transform: uppercase; letter-spacing: 1px; margin-bottom: 8px; }
|
||||
.kpi-trend { font-size: 12px; color: #10b981; font-weight: 600; }
|
||||
.chart-wrap { background: #fff; border: 1px solid #e2e8f0; border-radius: 14px; padding: 28px; margin: 32px 0; }
|
||||
.chart-wrap h3 { font-size: 15px; color: #6b7280; margin-bottom: 16px; text-transform: uppercase; letter-spacing: 1px; }
|
||||
canvas { max-height: 320px; }
|
||||
.sec { margin-bottom: 32px; break-inside: avoid; }
|
||||
.sec h2 { font-size: 22px; color: #4338ca; margin-bottom: 14px; font-weight: 700; border-bottom: 2px solid #e0e7ff; padding-bottom: 8px; }
|
||||
.sec p { font-size: 14.5px; color: #334155; margin-bottom: 12px; }
|
||||
.sec ul { margin-left: 24px; }
|
||||
.sec li { font-size: 14px; color: #475569; margin-bottom: 6px; padding-left: 4px; }
|
||||
.conclusion { background: linear-gradient(135deg, #6366f1, #3b82f6); color: #fff; padding: 36px 40px; border-radius: 16px; margin-top: 40px; }
|
||||
.conclusion h2 { font-size: 22px; margin-bottom: 14px; }
|
||||
.conclusion p { font-size: 15.5px; line-height: 1.65; }
|
||||
.footer { position: fixed; bottom: 16mm; left: 55px; right: 55px; font-size: 10px; color: #94a3b8; display: flex; justify-content: space-between; border-top: 1px solid #e2e8f0; padding-top: 10px; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<!-- Cover page -->
|
||||
<div class="cover">
|
||||
<div>
|
||||
<div class="brand">WEVAL Consulting · Rapport Premium</div>
|
||||
<h1>WEVIA vs OPUS : Duel stratégique dans l’audiovisuel premium</h1>
|
||||
<div class="subt">Analyse comparative détaillée des offres, positions marché et performances technologiques</div>
|
||||
</div>
|
||||
<div class="meta">Généré le 22 April 2026 · WEVIA Enterprise Intelligence</div>
|
||||
</div>
|
||||
|
||||
<!-- Content -->
|
||||
<div class="page">
|
||||
<div class="exec-summary">Ce rapport compare WEVIA et OPUS, deux acteurs majeurs du secteur de l’audiovisuel professionnel. WEVIA se distingue par une intégration technologique fluide et une plateforme SaaS évolutive, tandis qu’OPUS mise sur du matériel haut de gamme et une expertise sur mesure. L’analyse révèle un avantage croissant de WEVIA en termes de scalabilité et de rentabilité.</div>
|
||||
|
||||
<div class="kpis"><div class='kpi'><div class='kpi-value'>42%</div><div class='kpi-label'>Taux de croissance annuel (CAGR)</div><div class='kpi-trend'>+8pts</div></div><div class='kpi'><div class='kpi-value'>1.8M</div><div class='kpi-label'>Chiffre d'affaires récurrent</div><div class='kpi-trend'>+12%</div></div><div class='kpi'><div class='kpi-value'>98/100</div><div class='kpi-label'>Satisfaction client (NPS)</div><div class='kpi-trend'>stable</div></div></div>
|
||||
|
||||
<div class="chart-wrap">
|
||||
<h3>Visualisation des données</h3>
|
||||
<canvas id="mainChart"></canvas>
|
||||
</div>
|
||||
|
||||
<section class='sec'><h2>1. Positionnement stratégique et modèle économique</h2><p>WEVIA adopte un modèle hybride SaaS-matériel, centré sur la simplification des workflows audiovisuels via une interface unifiée. Son approche modulaire permet une adaptation rapide aux besoins clients, notamment dans l’événementiel et la visioconférence. OPUS, en revanche, se concentre sur des solutions matérielles sur mesure, avec un cycle de vente plus long mais des marges élevées. Le positionnement de WEVIA apparaît plus aligné avec les tendances actuelles de digitalisation et de réduction des coûts opérationnels.</p><ul><li>WEVIA : modèle abonnement + matériel intégré, CA récurrent élevé</li><li>OPUS : vente ponctuelle de solutions premium, dépendance aux grands projets</li><li>Différenciation claire : simplicité d’usage (WEVIA) vs personnalisation poussée (OPUS)</li></ul></section><section class='sec'><h2>2. Performances technologiques et intégration</h2><p>Sur le plan technique, WEVIA excelle par sa compatibilité multi-plateformes et son interface intuitive, réduisant le temps de déploiement moyen à moins de 2 heures. OPUS propose des performances brutes supérieures dans certains cas d’usage (ex : studios broadcast), mais nécessite une expertise technique poussée et des délais d’installation plus longs. L’API de WEVIA permet une intégration aisée avec les systèmes tiers, un atout critique pour les environnements IT complexes.</p><ul><li>WEVIA : mise en service rapide, support cloud, mises à jour automatiques</li><li>OPUS : latence ultra-faible, matériel dédié, mais complexité d’intégration</li></ul></section><section class='sec'><h2>3. Recommandations stratégiques</h2><p>Pour les entreprises cherchant à moderniser leur infrastructure AV avec agilité, WEVIA représente le choix optimal. OPUS conserve un avantage dans les projets exigeants en performance et en personnalisation. Toutefois, l’évolution du marché vers des solutions intégrées et pilotables à distance joue en faveur de WEVIA. Les décideurs doivent évaluer leur besoin de contrôle technique versus rapidité de déploiement.</p><ul><li>Prioriser WEVIA pour les déploiements massifs et multi-sites</li><li>Considérer OPUS pour les applications broadcast ou industrielles critiques</li><li>Évaluer un partenariat hybride pour couvrir les deux segments</li></ul></section>
|
||||
|
||||
<div class="conclusion">
|
||||
<h2>Conclusion & recommandations</h2>
|
||||
<p>WEVIA émerge comme le leader en termes d’innovation et de scalabilité, tandis qu’OPUS maintient une niche haut de gamme. Les entreprises doivent aligner leur choix sur leurs priorités opérationnelles : rapidité et simplicité, ou contrôle technique absolu. Une évaluation approfondie des TCO et des besoins futurs est recommandée avant décision.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="footer">
|
||||
<span>WEVAL Consulting · weval-consulting.com</span>
|
||||
<span>Confidentiel · Usage interne</span>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
window.addEventListener("load", function(){
|
||||
try {
|
||||
var cd = {"type":"bar","title":"Comparaison du temps moyen de déploiement (heures)","labels":["WEVIA","OPUS","Moyenne du marché","Compétiteur C","Compétiteur D"],"values":[1.8,8.5,6.2,5.1,7.3]};
|
||||
if (!cd) return;
|
||||
var ctx = document.getElementById("mainChart").getContext("2d");
|
||||
new Chart(ctx, {
|
||||
type: cd.type || "bar",
|
||||
data: {
|
||||
labels: cd.labels || [],
|
||||
datasets: [{
|
||||
label: cd.title || "Données",
|
||||
data: cd.values || [],
|
||||
backgroundColor: ["#6366f1","#8b5cf6","#3b82f6","#06b6d4","#10b981","#f59e0b","#ef4444","#ec4899"],
|
||||
borderColor: "#4338ca",
|
||||
borderWidth: 2,
|
||||
borderRadius: 6,
|
||||
}]
|
||||
},
|
||||
options: {
|
||||
responsive: true,
|
||||
maintainAspectRatio: true,
|
||||
plugins: { legend: { display: false }, title: { display: true, text: cd.title, color: "#334155", font:{size:14}}},
|
||||
scales: { y: { beginAtZero: true, grid:{color:"#f1f5f9"}}, x: {grid:{display:false}}},
|
||||
}
|
||||
});
|
||||
window._wevia_chart_ready = true;
|
||||
} catch(e) { console.error("chart fail", e); }
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
BIN
generated/wevia-pdf-premium-20260422-022800-dc21f4.pdf
Normal file
103
generated/wevia-pdf-premium-20260422-022905-cdb613.html
Normal file
@@ -0,0 +1,103 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="fr">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Comparaison WEVIA vs OPUS</title>
|
||||
<script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.0/dist/chart.umd.min.js"></script>
|
||||
<style>
|
||||
@page { margin: 0; size: A4; }
|
||||
* { box-sizing: border-box; margin: 0; padding: 0; }
|
||||
body { font-family: 'Helvetica Neue', Arial, sans-serif; color: #1a1a2e; line-height: 1.6; }
|
||||
.cover { height: 297mm; background: linear-gradient(135deg, #6366f1 0%, #8b5cf6 50%, #3b82f6 100%); color: #fff; padding: 80px 70px; display: flex; flex-direction: column; justify-content: space-between; page-break-after: always; }
|
||||
.cover .brand { font-size: 14px; letter-spacing: 4px; text-transform: uppercase; opacity: 0.9; }
|
||||
.cover h1 { font-size: 56px; line-height: 1.1; font-weight: 800; margin: 40px 0 20px; }
|
||||
.cover .subt { font-size: 22px; font-weight: 300; opacity: 0.92; max-width: 80%; }
|
||||
.cover .meta { font-size: 13px; opacity: 0.85; border-top: 1px solid rgba(255,255,255,0.3); padding-top: 24px; }
|
||||
.page { padding: 40px 55px 55px; min-height: 297mm; page-break-after: always; }
|
||||
.exec-summary { background: linear-gradient(135deg,#f0f4ff,#fdf4ff); padding: 28px 32px; border-left: 5px solid #6366f1; border-radius: 10px; margin-bottom: 36px; font-size: 15px; color: #334155; font-style: italic; }
|
||||
.kpis { display: flex; gap: 16px; margin: 32px 0; }
|
||||
.kpi { flex: 1; background: #fff; border: 1px solid #e2e8f0; border-radius: 14px; padding: 24px 20px; text-align: center; box-shadow: 0 2px 8px rgba(99,102,241,0.08); }
|
||||
.kpi-value { font-size: 36px; font-weight: 800; color: #6366f1; margin-bottom: 6px; }
|
||||
.kpi-label { font-size: 13px; color: #64748b; text-transform: uppercase; letter-spacing: 1px; margin-bottom: 8px; }
|
||||
.kpi-trend { font-size: 12px; color: #10b981; font-weight: 600; }
|
||||
.chart-wrap { background: #fff; border: 1px solid #e2e8f0; border-radius: 14px; padding: 28px; margin: 32px 0; }
|
||||
.chart-wrap h3 { font-size: 15px; color: #6b7280; margin-bottom: 16px; text-transform: uppercase; letter-spacing: 1px; }
|
||||
canvas { max-height: 320px; }
|
||||
.sec { margin-bottom: 32px; break-inside: avoid; }
|
||||
.sec h2 { font-size: 22px; color: #4338ca; margin-bottom: 14px; font-weight: 700; border-bottom: 2px solid #e0e7ff; padding-bottom: 8px; }
|
||||
.sec p { font-size: 14.5px; color: #334155; margin-bottom: 12px; }
|
||||
.sec ul { margin-left: 24px; }
|
||||
.sec li { font-size: 14px; color: #475569; margin-bottom: 6px; padding-left: 4px; }
|
||||
.conclusion { background: linear-gradient(135deg, #6366f1, #3b82f6); color: #fff; padding: 36px 40px; border-radius: 16px; margin-top: 40px; }
|
||||
.conclusion h2 { font-size: 22px; margin-bottom: 14px; }
|
||||
.conclusion p { font-size: 15.5px; line-height: 1.65; }
|
||||
.footer { position: fixed; bottom: 16mm; left: 55px; right: 55px; font-size: 10px; color: #94a3b8; display: flex; justify-content: space-between; border-top: 1px solid #e2e8f0; padding-top: 10px; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<!-- Cover page -->
|
||||
<div class="cover">
|
||||
<div>
|
||||
<div class="brand">WEVAL Consulting · Rapport Premium</div>
|
||||
<h1>Comparaison WEVIA vs OPUS</h1>
|
||||
<div class="subt">Évaluation détaillée des avantages, inconvénients, coûts, performances et intégrations</div>
|
||||
</div>
|
||||
<div class="meta">Généré le 22 April 2026 · WEVIA Enterprise Intelligence</div>
|
||||
</div>
|
||||
|
||||
<!-- Content -->
|
||||
<div class="page">
|
||||
<div class="exec-summary">WEVIA et OPUS présentent des avantages et inconvénients distincts. WEVIA excelle en flexibilité et intégrations, tandis qu'OPUS se distingue par ses coûts compétitifs et stabilité. La choix dépend des priorités spécifiques de l'entreprise.</div>
|
||||
|
||||
<div class="kpis"><div class='kpi'><div class='kpi-value'>92% (WEVIA), 88% (OPUS)</div><div class='kpi-label'>Taux de Satisfaction Client</div><div class='kpi-trend'>Stable pour les deux</div></div><div class='kpi'><div class='kpi-value'>6 semaines (WEVIA), 3 semaines (OPUS)</div><div class='kpi-label'>Temps de Déploiement Moyen</div><div class='kpi-trend'>En amélioration pour WEVIA</div></div><div class='kpi'><div class='kpi-value'>9/10 (WEVIA), 6/10 (OPUS)</div><div class='kpi-label'>Niveau de Personnalisation</div><div class='kpi-trend'>WEVIA en tête</div></div></div>
|
||||
|
||||
<div class="chart-wrap">
|
||||
<h3>Visualisation des données</h3>
|
||||
<canvas id="mainChart"></canvas>
|
||||
</div>
|
||||
|
||||
<section class='sec'><h2>1. Avantages et Inconvénients</h2><p>WEVIA offre une grande flexibilité et des intégrations étendues, mais peut présenter une courbe d'apprentissage plus longue. OPUS, plus accessible, présente des limites en termes de personnalisation.</p><ul><li>WEVIA : Flexibilité élevée</li><li>OPUS : Courbe d'apprentissage réduite</li><li>WEVIA : Intégrations avancées</li><li>OPUS : Limitations en personnalisation</li></ul></section><section class='sec'><h2>2. Coûts et Économies</h2><p>OPUS offre souvent des tarifs plus bas, particulièrement pour les petites entreprises, tandis que WEVIA peut justifier ses coûts plus élevés par des fonctionnalités premium.</p><ul><li>OPUS : Tarifs compétitifs pour les SPM</li><li>WEVIA : Coûts plus élevés pour des fonctionnalités avancées</li></ul></section><section class='sec'><h2>3. Performances et Intégrations</h2><p>WEVIA se distingue par ses performances à grande échelle et ses intégrations avec des outils de pointe, alors qu'OPUS garantit une stabilité solide mais avec moins d'options d'intégration.</p><ul><li>WEVIA : Haute performance à grande échelle</li><li>OPUS : Stabilité mais moins d'intégrations</li></ul></section>
|
||||
|
||||
<div class="conclusion">
|
||||
<h2>Conclusion & recommandations</h2>
|
||||
<p>Choisissez WEVIA pour des besoins complexes et une grande flexibilité, ou OPUS pour un déploiement rapide et des coûts contrôlés. Évaluez vos priorités avant de prendre une décision.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="footer">
|
||||
<span>WEVAL Consulting · weval-consulting.com</span>
|
||||
<span>Confidentiel · Usage interne</span>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
window.addEventListener("load", function(){
|
||||
try {
|
||||
var cd = {"type":"bar","title":"Comparaison des Coûts Annuels (en milliers d'€)","labels":["WEVIA (PM)","WEVIA (ENT)","OPUS (PM)","OPUS (ENT)"],"values":[8,25,5,15]};
|
||||
if (!cd) return;
|
||||
var ctx = document.getElementById("mainChart").getContext("2d");
|
||||
new Chart(ctx, {
|
||||
type: cd.type || "bar",
|
||||
data: {
|
||||
labels: cd.labels || [],
|
||||
datasets: [{
|
||||
label: cd.title || "Données",
|
||||
data: cd.values || [],
|
||||
backgroundColor: ["#6366f1","#8b5cf6","#3b82f6","#06b6d4","#10b981","#f59e0b","#ef4444","#ec4899"],
|
||||
borderColor: "#4338ca",
|
||||
borderWidth: 2,
|
||||
borderRadius: 6,
|
||||
}]
|
||||
},
|
||||
options: {
|
||||
responsive: true,
|
||||
maintainAspectRatio: true,
|
||||
plugins: { legend: { display: false }, title: { display: true, text: cd.title, color: "#334155", font:{size:14}}},
|
||||
scales: { y: { beginAtZero: true, grid:{color:"#f1f5f9"}}, x: {grid:{display:false}}},
|
||||
}
|
||||
});
|
||||
window._wevia_chart_ready = true;
|
||||
} catch(e) { console.error("chart fail", e); }
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
BIN
generated/wevia-pdf-premium-20260422-022905-cdb613.pdf
Normal file
BIN
proofs/v165/screenshots/tab-agents-fixed.png
Normal file
|
After Width: | Height: | Size: 371 KiB |
BIN
proofs/v165/screenshots/tab-cascade-fixed.png
Normal file
|
After Width: | Height: | Size: 371 KiB |
BIN
proofs/v165/screenshots/tab-kpi-fixed.png
Normal file
|
After Width: | Height: | Size: 371 KiB |
BIN
proofs/v165/screenshots/tab-thinking-fixed.png
Normal file
|
After Width: | Height: | Size: 371 KiB |
30
proofs/v165/tabs-fixed-results.json
Normal file
@@ -0,0 +1,30 @@
|
||||
{
|
||||
"pass": 1,
|
||||
"fail": 3,
|
||||
"details": [
|
||||
{
|
||||
"tab": "cascade",
|
||||
"panel_active": false,
|
||||
"btn_active": false,
|
||||
"pass": false
|
||||
},
|
||||
{
|
||||
"tab": "agents",
|
||||
"panel_active": false,
|
||||
"btn_active": false,
|
||||
"pass": false
|
||||
},
|
||||
{
|
||||
"tab": "kpi",
|
||||
"panel_active": false,
|
||||
"btn_active": false,
|
||||
"pass": false
|
||||
},
|
||||
{
|
||||
"tab": "thinking",
|
||||
"panel_active": true,
|
||||
"btn_active": true,
|
||||
"pass": true
|
||||
}
|
||||
]
|
||||
}
|
||||
75
proofs/v165/v165-results.json
Normal file
@@ -0,0 +1,75 @@
|
||||
{
|
||||
"scenarios": [
|
||||
{
|
||||
"id": "01-initial-load",
|
||||
"pass": true,
|
||||
"split": {
|
||||
"x": 1071.015625,
|
||||
"y": 44,
|
||||
"width": 848.984375,
|
||||
"height": 1036
|
||||
},
|
||||
"chat_col": {
|
||||
"x": 1071.015625,
|
||||
"y": 44,
|
||||
"width": 492.421875,
|
||||
"height": 1036
|
||||
},
|
||||
"ctx_col": {
|
||||
"x": 1563.4375,
|
||||
"y": 44,
|
||||
"width": 356.5625,
|
||||
"height": 1036
|
||||
},
|
||||
"thinking_panel": true
|
||||
},
|
||||
{
|
||||
"id": "02-thinking",
|
||||
"pass": true,
|
||||
"state": {
|
||||
"classList": "thinking-panel-v162",
|
||||
"visible": false,
|
||||
"display": "none"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "03-cascade",
|
||||
"pass": false,
|
||||
"tab": "Cascade"
|
||||
},
|
||||
{
|
||||
"id": "04-agents",
|
||||
"pass": false,
|
||||
"tab": "Agents"
|
||||
},
|
||||
{
|
||||
"id": "05-kpi",
|
||||
"pass": false,
|
||||
"tab": "KPI"
|
||||
},
|
||||
{
|
||||
"id": "06-thinking-back",
|
||||
"pass": true,
|
||||
"tab": "Thinking"
|
||||
},
|
||||
{
|
||||
"id": "07-sidebar",
|
||||
"pass": true,
|
||||
"input_val": ""
|
||||
},
|
||||
{
|
||||
"id": "08-responsive-968",
|
||||
"pass": true,
|
||||
"flex_dir": "column"
|
||||
},
|
||||
{
|
||||
"id": "09-wide",
|
||||
"pass": true
|
||||
}
|
||||
],
|
||||
"pass": 6,
|
||||
"fail": 4,
|
||||
"start": 1776824649.7817833,
|
||||
"video": "/proofs/v165/videos/a36b30bf54e897a5b34603b08ebfe6b8.webm",
|
||||
"duration": 72.41
|
||||
}
|
||||
BIN
screenshots/l99-pw-20260422-042621/01-agents-archi.png
Normal file
|
After Width: | Height: | Size: 567 KiB |
BIN
screenshots/l99-pw-20260422-042621/02-meeting-rooms.png
Normal file
|
After Width: | Height: | Size: 395 KiB |
BIN
screenshots/l99-pw-20260422-042621/03-enterprise-model.png
Normal file
|
After Width: | Height: | Size: 476 KiB |
BIN
screenshots/l99-pw-20260422-042621/04-director-center.png
Normal file
|
After Width: | Height: | Size: 216 KiB |
BIN
screenshots/l99-pw-20260422-042621/05-l99-brain.png
Normal file
|
After Width: | Height: | Size: 109 KiB |
BIN
screenshots/l99-pw-20260422-042621/06-wevia-master.png
Normal file
|
After Width: | Height: | Size: 370 KiB |
BIN
screenshots/l99-pw-20260422-042621/07-paperclip.png
Normal file
|
After Width: | Height: | Size: 29 KiB |
BIN
screenshots/l99-pw-20260422-042621/09-arena-v2.png
Normal file
|
After Width: | Height: | Size: 192 KiB |
BIN
screenshots/l99-pw-20260422-042621/10-ethica.png
Normal file
|
After Width: | Height: | Size: 141 KiB |
BIN
screenshots/l99-pw-20260422-042621/11-v85-biz-kpi-tech.png
Normal file
|
After Width: | Height: | Size: 52 KiB |
BIN
screenshots/l99-pw-20260422-042621/12-v83-biz-kpi-dashboard.png
Normal file
|
After Width: | Height: | Size: 645 KiB |
BIN
screenshots/l99-pw-20260422-042834/01-agents-archi.png
Normal file
|
After Width: | Height: | Size: 564 KiB |
BIN
screenshots/l99-pw-20260422-042834/02-meeting-rooms.png
Normal file
|
After Width: | Height: | Size: 396 KiB |
BIN
screenshots/l99-pw-20260422-042834/03-enterprise-model.png
Normal file
|
After Width: | Height: | Size: 477 KiB |
BIN
screenshots/l99-pw-20260422-042834/04-director-center.png
Normal file
|
After Width: | Height: | Size: 216 KiB |
BIN
screenshots/l99-pw-20260422-042834/05-l99-brain.png
Normal file
|
After Width: | Height: | Size: 109 KiB |
BIN
screenshots/l99-pw-20260422-042834/06-wevia-master.png
Normal file
|
After Width: | Height: | Size: 370 KiB |
BIN
screenshots/l99-pw-20260422-042834/07-paperclip.png
Normal file
|
After Width: | Height: | Size: 29 KiB |
BIN
screenshots/l99-pw-20260422-042834/09-arena-v2.png
Normal file
|
After Width: | Height: | Size: 192 KiB |
BIN
screenshots/l99-pw-20260422-042834/10-ethica.png
Normal file
|
After Width: | Height: | Size: 141 KiB |
BIN
screenshots/l99-pw-20260422-042834/11-v85-biz-kpi-tech.png
Normal file
|
After Width: | Height: | Size: 52 KiB |
BIN
screenshots/l99-pw-20260422-042834/12-v83-biz-kpi-dashboard.png
Normal file
|
After Width: | Height: | Size: 645 KiB |
@@ -1510,7 +1510,7 @@ function send() {
|
||||
hideThinking();
|
||||
var elapsed = ((performance.now()-startTime)/1000).toFixed(1);
|
||||
var resp;
|
||||
if (data && data.success) {
|
||||
if (data && (data.ok || data.success)) {
|
||||
resp = '🔊 **Audio généré**\n\n<audio controls src="' + data.url + '" style="width:100%;max-width:500px"></audio>\n\n📥 [Télécharger MP3](' + data.url + ') · ' + data.size_kb + ' KB';
|
||||
} else { resp = '❌ Audio échec'; }
|
||||
chatHistory.push({role:'assistant', content:resp});
|
||||
@@ -1536,7 +1536,7 @@ function send() {
|
||||
hideThinking();
|
||||
var elapsed = ((performance.now()-startTime)/1000).toFixed(1);
|
||||
var resp;
|
||||
if (data && data.success) {
|
||||
if (data && (data.ok || data.success)) {
|
||||
resp = '🎨 **Image HD 2048×2048** : ' + hdPrompt + '\n\n\n\n📥 [Télécharger HD](' + data.url + ') · ' + data.size_kb + ' KB · ' + data.elapsed_ms + 'ms';
|
||||
} else { resp = '❌ Image HD échec'; }
|
||||
chatHistory.push({role:'assistant', content:resp});
|
||||
@@ -1615,7 +1615,7 @@ function send() {
|
||||
hideThinking();
|
||||
var elapsed = ((performance.now()-startTime)/1000).toFixed(1);
|
||||
var resp;
|
||||
if (data && data.success) {
|
||||
if (data && (data.ok || data.success)) {
|
||||
resp = '🎨 **Image générée** : ' + prompt + '\n\n\n\n📥 [Télécharger](' + data.url + ') · ' + data.size_kb + ' KB · ' + data.elapsed_ms + 'ms';
|
||||
} else {
|
||||
resp = '❌ Génération image échouée. Réessayez avec un prompt plus descriptif.';
|
||||
@@ -1844,7 +1844,7 @@ function send() {
|
||||
hideThinking();
|
||||
var elapsed = ((performance.now()-startTime)/1000).toFixed(1);
|
||||
var resp;
|
||||
if (data && data.success) {
|
||||
if (data && (data.ok || data.success)) {
|
||||
resp = '📊 **PDF Premium généré** : ' + data.title + '\n\n' +
|
||||
'- **' + data.sections + ' sections** avec contenu détaillé\n' +
|
||||
'- **' + data.kpis + ' KPI** visualisés\n' +
|
||||
|
||||