auto-sync-0430

This commit is contained in:
opus
2026-04-22 04:30:07 +02:00
parent 1d65fb4959
commit 61429584fa
52 changed files with 924 additions and 1976 deletions

View File

@@ -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,

View File

@@ -0,0 +1,4 @@
{
"status": "passed",
"failedTests": []
}

View 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
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 88 KiB

After

Width:  |  Height:  |  Size: 90 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 341 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 393 KiB

23
api/ambre-v9-ok.php Normal file
View 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,
]);

File diff suppressed because it is too large Load Diff

View File

@@ -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,

View File

@@ -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));

View 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);

Binary file not shown.

After

Width:  |  Height:  |  Size: 303 KiB

View File

@@ -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,

View File

@@ -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)) {

View File

@@ -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)];

View File

@@ -0,0 +1,103 @@
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<title>WEVIA vs OPUS : Duel stratégique dans laudiovisuel 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 laudiovisuel 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 laudiovisuel professionnel. WEVIA se distingue par une intégration technologique fluide et une plateforme SaaS évolutive, tandis quOPUS mise sur du matériel haut de gamme et une expertise sur mesure. Lanalyse 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&#039;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é dusage (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 dusage (ex : studios broadcast), mais nécessite une expertise technique poussée et des délais dinstallation plus longs. LAPI 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é dinté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 dinnovation et de scalabilité, tandis quOPUS 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>

Binary file not shown.

View 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&#039;OPUS se distingue par ses coûts compétitifs et stabilité. La choix dépend des priorités spécifiques de l&#039;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&#039;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&#039;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&#039;OPUS garantit une stabilité solide mais avec moins d&#039;options d&#039;intégration.</p><ul><li>WEVIA : Haute performance à grande échelle</li><li>OPUS : Stabilité mais moins d&#039;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>

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 371 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 371 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 371 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 371 KiB

View 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
}
]
}

View 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
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 567 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 395 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 476 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 216 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 109 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 370 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 192 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 141 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 645 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 564 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 396 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 477 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 216 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 109 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 370 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 192 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 141 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 645 KiB

View File

@@ -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![HD](' + data.url + ')\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![image](' + data.url + ')\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' +