This commit is contained in:
5
api/ambre-kill25.php
Normal file
5
api/ambre-kill25.php
Normal file
@@ -0,0 +1,5 @@
|
||||
<?php
|
||||
header("Content-Type: text/plain");
|
||||
@shell_exec("pkill -f playwright 2>&1");
|
||||
echo "killed\n";
|
||||
echo @shell_exec("pgrep -af playwright | head -5");
|
||||
Binary file not shown.
Binary file not shown.
|
Before Width: | Height: | Size: 64 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 86 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 97 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 96 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 112 KiB |
@@ -1,125 +0,0 @@
|
||||
const { test } = require("@playwright/test");
|
||||
const fs = require("fs");
|
||||
|
||||
test("V25 · FINAL · after mermaid fix · 10 turns incl PDF Premium · video longue", async ({ page }) => {
|
||||
test.setTimeout(900000);
|
||||
|
||||
const errors = [];
|
||||
page.on("pageerror", e => errors.push("PE: " + e.message.substring(0,200)));
|
||||
page.on("console", msg => {
|
||||
if (msg.type() === "error" || msg.type() === "warning") {
|
||||
errors.push(msg.type() + ": " + msg.text().substring(0,200));
|
||||
}
|
||||
});
|
||||
|
||||
await page.goto("/wevia.html");
|
||||
await page.evaluate(() => { try { sessionStorage.clear(); } catch(e){} });
|
||||
await page.waitForLoadState("networkidle");
|
||||
await page.waitForTimeout(3000);
|
||||
|
||||
console.log("=== Errors on load ===");
|
||||
errors.forEach(e => console.log(" ", e));
|
||||
|
||||
await page.screenshot({ path: "output/v25-00-landing.png" });
|
||||
|
||||
// Check global functions
|
||||
const funcs = await page.evaluate(() => ({
|
||||
sendMsg: typeof window.sendMsg,
|
||||
send: typeof window.send,
|
||||
addMsg: typeof window.addMsg,
|
||||
}));
|
||||
console.log("\n=== Global functions ===", JSON.stringify(funcs));
|
||||
|
||||
const turns = [
|
||||
{ label: "01-intro", msg: "Bonjour", needle: /aider|ravi|bienvenue/i },
|
||||
{ label: "02-identity", msg: "je m'appelle Claire, directrice innovation chez BNP Paribas", needle: /Claire/i },
|
||||
{ label: "03-calc", msg: "calcule (789 * 1.15 + 250) / 4", needle: /\d{3,}/ },
|
||||
{ label: "04-qr", msg: "QR code pour https://bnpparibas.com", needle: /wevia-qr-|📱/i },
|
||||
{ label: "05-pdf-premium", msg: "cree un pdf premium sur: strategie IA banque 2026 avec graphiques", needle: /pdf-premium|Chart\.js|Télécharger/i },
|
||||
{ label: "06-search", msg: "actualités fintech 2026", needle: /🔍|source|fintech/i },
|
||||
{ label: "07-recall", msg: "comment je m'appelle et où je travaille?", needle: /Claire.*BNP|BNP.*Claire/i },
|
||||
{ label: "08-emotion", msg: "je suis un peu débordée avec tous mes projets", needle: /comprends|pression|gérer|pause/i },
|
||||
{ label: "09-subject", msg: "change de sujet, parle moi des dauphins", needle: /dauphin|cétacé|mammifère|intelligent|océan/i },
|
||||
{ label: "10-bilan", msg: "fais le bilan de notre échange aujourd'hui", needle: /Claire|BNP|PDF|IA|dauphin|calc|QR/i },
|
||||
];
|
||||
|
||||
const results = [];
|
||||
|
||||
for (let i = 0; i < turns.length; i++) {
|
||||
const t = turns[i];
|
||||
const num = String(i + 1).padStart(2, "0");
|
||||
console.log(`\n═══ [${num}/${turns.length}] ${t.label} ═══`);
|
||||
console.log(` → ${t.msg.substring(0, 100)}`);
|
||||
|
||||
const beforeCount = await page.evaluate(() => document.querySelectorAll('.msg.assistant').length);
|
||||
|
||||
try {
|
||||
const input = page.locator("#msgInput");
|
||||
await input.click({ force: true });
|
||||
await page.keyboard.press("Control+A");
|
||||
await page.keyboard.press("Delete");
|
||||
await input.fill(t.msg);
|
||||
await page.waitForTimeout(500);
|
||||
await input.press("Enter");
|
||||
|
||||
const timeout = t.label.includes("pdf-premium") ? 90000 : 50000;
|
||||
const waitStart = Date.now();
|
||||
let found = false;
|
||||
let assistantReply = "";
|
||||
|
||||
while (Date.now() - waitStart < timeout) {
|
||||
const state = await page.evaluate(() => {
|
||||
const a = Array.from(document.querySelectorAll(".msg.assistant .bubble"));
|
||||
return {
|
||||
count: a.length,
|
||||
last: a.length > 0 ? a[a.length-1].innerText : "",
|
||||
};
|
||||
});
|
||||
|
||||
if (state.count > beforeCount) {
|
||||
assistantReply = state.last;
|
||||
// Skip if still showing error (may retry)
|
||||
if (/erreur est survenue/i.test(assistantReply) && (Date.now() - waitStart) < 15000) {
|
||||
await page.waitForTimeout(2500);
|
||||
continue;
|
||||
}
|
||||
if (t.needle.test(assistantReply)) { found = true; break; }
|
||||
if (assistantReply.length > 40 && !assistantReply.includes("erreur est")) {
|
||||
// got real reply, check needle
|
||||
if (t.needle.test(assistantReply)) { found = true; break; }
|
||||
}
|
||||
}
|
||||
await page.waitForTimeout(2000);
|
||||
}
|
||||
|
||||
const elapsed = ((Date.now() - waitStart) / 1000).toFixed(1);
|
||||
const isError = /erreur est survenue/i.test(assistantReply);
|
||||
|
||||
if (found) console.log(` ✅ PASS ${elapsed}s · ${assistantReply.substring(0,100)}`);
|
||||
else if (isError) console.log(` ❌ ERROR ${elapsed}s`);
|
||||
else console.log(` ⚠️ NO MATCH ${elapsed}s · reply: ${assistantReply.substring(0,150)}`);
|
||||
|
||||
await page.evaluate(() => { const m = document.getElementById("messages"); if (m) m.scrollTop = m.scrollHeight; });
|
||||
await page.waitForTimeout(2500);
|
||||
await page.screenshot({ path: `output/v25-${num}-${t.label}.png`, fullPage: false });
|
||||
|
||||
results.push({ turn: i+1, label: t.label, pass: found, error: isError, elapsed, reply_preview: assistantReply.substring(0,180) });
|
||||
await page.waitForTimeout(1500);
|
||||
} catch (e) {
|
||||
console.log(` ❌ EXCEPTION: ${e.message.substring(0, 120)}`);
|
||||
results.push({ turn: i+1, label: t.label, pass: false, error: true });
|
||||
}
|
||||
}
|
||||
|
||||
await page.evaluate(() => window.scrollTo(0, document.body.scrollHeight));
|
||||
await page.waitForTimeout(3000);
|
||||
await page.screenshot({ path: "output/v25-99-final.png", fullPage: true });
|
||||
|
||||
const pass = results.filter(r=>r.pass).length;
|
||||
const errors2 = results.filter(r=>r.error).length;
|
||||
console.log(`\n═══════════════ V25 BILAN ═══════════════`);
|
||||
console.log(`${pass}/${results.length} PASS · ${errors2} errors`);
|
||||
results.forEach(r => console.log(` ${r.pass?"✅":(r.error?"❌":"⚠️")} T${r.turn} · ${r.label} · ${r.elapsed||"?"}s`));
|
||||
|
||||
fs.writeFileSync("output/v25-results.json", JSON.stringify({ results, pass, total: results.length, load_errors: errors }, null, 2));
|
||||
});
|
||||
56
api/ambre-pw-tests/tests/v28-fetch-log.spec.js
Normal file
56
api/ambre-pw-tests/tests/v28-fetch-log.spec.js
Normal file
@@ -0,0 +1,56 @@
|
||||
const { test } = require("@playwright/test");
|
||||
|
||||
test("V28 · wrap fetch and send HI", async ({ page }) => {
|
||||
test.setTimeout(60000);
|
||||
|
||||
const netlog = [];
|
||||
const errs = [];
|
||||
page.on("pageerror", e => errs.push(e.message));
|
||||
page.on("response", res => {
|
||||
if (res.url().includes("/api/")) {
|
||||
netlog.push({ url: res.url().split("?")[0], status: res.status() });
|
||||
}
|
||||
});
|
||||
|
||||
await page.goto("/wevia.html");
|
||||
await page.waitForTimeout(2500);
|
||||
|
||||
// Monkey-patch fetch to see all calls
|
||||
await page.evaluate(() => {
|
||||
window._fetchLog = [];
|
||||
const orig = window.fetch;
|
||||
window.fetch = function(u, opts) {
|
||||
const url = typeof u === "string" ? u : u.url;
|
||||
window._fetchLog.push({ url: url.split("?")[0], method: (opts && opts.method) || "GET" });
|
||||
return orig.apply(this, arguments);
|
||||
};
|
||||
});
|
||||
|
||||
// Send "HI"
|
||||
await page.fill("#msgInput", "HI");
|
||||
await page.waitForTimeout(300);
|
||||
await page.press("#msgInput", "Enter");
|
||||
|
||||
await page.waitForTimeout(15000);
|
||||
|
||||
const fetchLog = await page.evaluate(() => window._fetchLog);
|
||||
console.log("\n=== fetch calls from JS ===");
|
||||
console.log(JSON.stringify(fetchLog, null, 2));
|
||||
|
||||
console.log("\n=== Network log (via Playwright) ===");
|
||||
console.log(JSON.stringify(netlog, null, 2));
|
||||
|
||||
console.log("\n=== Page errors ===");
|
||||
errs.forEach(e => console.log(" ", e.substring(0, 200)));
|
||||
|
||||
// DOM state
|
||||
const domState = await page.evaluate(() => {
|
||||
const a = document.querySelectorAll(".msg.assistant .bubble");
|
||||
return {
|
||||
count: a.length,
|
||||
messages: Array.from(a).map(el => el.innerText.substring(0, 200)),
|
||||
};
|
||||
});
|
||||
console.log("\n=== DOM messages ===");
|
||||
console.log(JSON.stringify(domState, null, 2));
|
||||
});
|
||||
7
api/ambre-pw-v26-deploy.php
Normal file
7
api/ambre-pw-v26-deploy.php
Normal file
@@ -0,0 +1,7 @@
|
||||
<?php
|
||||
header("Content-Type: application/json");
|
||||
$base = "/var/www/html/api/ambre-pw-tests/tests";
|
||||
$spec = base64_decode("Y29uc3QgeyB0ZXN0IH0gPSByZXF1aXJlKCJAcGxheXdyaWdodC90ZXN0Iik7Cgp0ZXN0KCJWMjYgwrcgQ0RQIGZpbmQgZXhhY3QgcmVnZXggZXJyb3IiLCBhc3luYyAoeyBicm93c2VyIH0pID0+IHsKICB0ZXN0LnNldFRpbWVvdXQoNjAwMDApOwogIGNvbnN0IGNvbnRleHQgPSBhd2FpdCBicm93c2VyLm5ld0NvbnRleHQoKTsKICBjb25zdCBwYWdlID0gYXdhaXQgY29udGV4dC5uZXdQYWdlKCk7CiAgCiAgLy8gVXNlIENEUCB0byBnZXQgZGV0YWlsZWQgZXJyb3JzCiAgY29uc3QgY2xpZW50ID0gYXdhaXQgY29udGV4dC5uZXdDRFBTZXNzaW9uKHBhZ2UpOwogIGF3YWl0IGNsaWVudC5zZW5kKCJSdW50aW1lLmVuYWJsZSIpOwogIGF3YWl0IGNsaWVudC5zZW5kKCJEZWJ1Z2dlci5lbmFibGUiKTsKICAKICBjb25zdCBleGNlcHRpb25zID0gW107CiAgY2xpZW50Lm9uKCJSdW50aW1lLmV4Y2VwdGlvblRocm93biIsIChwYXJhbXMpID0+IHsKICAgIGV4Y2VwdGlvbnMucHVzaChwYXJhbXMuZXhjZXB0aW9uRGV0YWlscyk7CiAgfSk7CiAgCiAgYXdhaXQgcGFnZS5nb3RvKCIvd2V2aWEuaHRtbCIpOwogIGF3YWl0IHBhZ2Uud2FpdEZvclRpbWVvdXQoNDAwMCk7CiAgCiAgY29uc29sZS5sb2coIj09PSBDRFAgZXhjZXB0aW9ucyBjb3VudDoiLCBleGNlcHRpb25zLmxlbmd0aCk7CiAgZm9yIChjb25zdCBlIG9mIGV4Y2VwdGlvbnMpIHsKICAgIGNvbnNvbGUubG9nKCJcbi0tLSBFeGNlcHRpb24gLS0tIik7CiAgICBjb25zb2xlLmxvZygidGV4dDoiLCBlLnRleHQpOwogICAgY29uc29sZS5sb2coInVybDoiLCBlLnVybCk7CiAgICBjb25zb2xlLmxvZygibGluZToiLCBlLmxpbmVOdW1iZXIpOwogICAgY29uc29sZS5sb2coImNvbDoiLCBlLmNvbHVtbk51bWJlcik7CiAgICBpZiAoZS5leGNlcHRpb24pIHsKICAgICAgY29uc29sZS5sb2coImRlc2NyaXB0aW9uOiIsIGUuZXhjZXB0aW9uLmRlc2NyaXB0aW9uID8gZS5leGNlcHRpb24uZGVzY3JpcHRpb24uc3Vic3RyaW5nKDAsIDE1MDApIDogIiIpOwogICAgfQogICAgaWYgKGUuc3RhY2tUcmFjZSkgewogICAgICBjb25zb2xlLmxvZygic3RhY2s6IiwgSlNPTi5zdHJpbmdpZnkoZS5zdGFja1RyYWNlLmNhbGxGcmFtZXMsIG51bGwsIDIpLnN1YnN0cmluZygwLCAxNTAwKSk7CiAgICB9CiAgfQp9KTsK");
|
||||
foreach (glob("$base/*.spec.js") as $old) @unlink($old);
|
||||
$written = @file_put_contents("$base/v26-cdp.spec.js", $spec);
|
||||
echo json_encode(["written" => $written]);
|
||||
7
api/ambre-pw-v27-deploy.php
Normal file
7
api/ambre-pw-v27-deploy.php
Normal file
@@ -0,0 +1,7 @@
|
||||
<?php
|
||||
header("Content-Type: application/json");
|
||||
$base = "/var/www/html/api/ambre-pw-tests/tests";
|
||||
$spec = base64_decode("Y29uc3QgeyB0ZXN0IH0gPSByZXF1aXJlKCJAcGxheXdyaWdodC90ZXN0Iik7Cgp0ZXN0KCJWMjcgwrcgdGVzdCBlYWNoIHNjcmlwdCB3aXRoIG5ldyBGdW5jdGlvbiBpbiBicm93c2VyIiwgYXN5bmMgKHsgcGFnZSB9KSA9PiB7CiAgdGVzdC5zZXRUaW1lb3V0KDYwMDAwKTsKICBhd2FpdCBwYWdlLmdvdG8oIi93ZXZpYS5odG1sIik7CiAgYXdhaXQgcGFnZS53YWl0Rm9yVGltZW91dCgyNTAwKTsKICAKICAvLyBGZXRjaCB0aGUgSFRNTCBzb3VyY2UgYW5kIHBhcnNlIGVhY2ggaW5saW5lIDxzY3JpcHQ+IHZpYSBuZXcgRnVuY3Rpb24KICBjb25zdCByZXN1bHQgPSBhd2FpdCBwYWdlLmV2YWx1YXRlKGFzeW5jICgpID0+IHsKICAgIGNvbnN0IHIgPSBhd2FpdCBmZXRjaCgnL3dldmlhLmh0bWwnKTsKICAgIGNvbnN0IGh0bWwgPSBhd2FpdCByLnRleHQoKTsKICAgIAogICAgLy8gRXh0cmFjdCBpbmxpbmUgc2NyaXB0cyAobm8gc3JjIGF0dHJpYnV0ZSkKICAgIGNvbnN0IHNjcmlwdHMgPSBbXTsKICAgIGNvbnN0IHJlID0gLzxzY3JpcHQoPyFbXj5dKlxzc3JjPSlbXj5dKj4oW1xzXFNdKj8pPFwvc2NyaXB0Pi9naTsKICAgIGxldCBtOwogICAgbGV0IGlkeCA9IDA7CiAgICB3aGlsZSAoKG0gPSByZS5leGVjKGh0bWwpKSAhPT0gbnVsbCkgewogICAgICBpZHgrKzsKICAgICAgY29uc3QgY29udGVudCA9IG1bMV07CiAgICAgIGlmIChjb250ZW50Lmxlbmd0aCA8IDIwKSBjb250aW51ZTsKICAgICAgY29uc3Qgc3RhcnRMaW5lID0gaHRtbC5zdWJzdHJpbmcoMCwgbS5pbmRleCkuc3BsaXQoJ1xuJykubGVuZ3RoOwogICAgICAKICAgICAgLy8gVHJ5IHRvIHBhcnNlIHZpYSBuZXcgRnVuY3Rpb24KICAgICAgbGV0IHBhcnNlRXJyID0gbnVsbDsKICAgICAgdHJ5IHsKICAgICAgICBuZXcgRnVuY3Rpb24oY29udGVudCk7CiAgICAgIH0gY2F0Y2ggKGUpIHsKICAgICAgICBwYXJzZUVyciA9IHsgbXNnOiBlLm1lc3NhZ2UsIHN0YWNrOiAoZS5zdGFjayB8fCAnJykuc3Vic3RyaW5nKDAsIDgwMCkgfTsKICAgICAgfQogICAgICAKICAgICAgc2NyaXB0cy5wdXNoKHsKICAgICAgICBpZHgsCiAgICAgICAgc3RhcnRMaW5lLAogICAgICAgIHNpemU6IGNvbnRlbnQubGVuZ3RoLAogICAgICAgIHBhcnNlRXJyLAogICAgICB9KTsKICAgIH0KICAgIHJldHVybiBzY3JpcHRzOwogIH0pOwogIAogIGNvbnNvbGUubG9nKEpTT04uc3RyaW5naWZ5KHJlc3VsdCwgbnVsbCwgMikpOwp9KTsK");
|
||||
foreach (glob("$base/*.spec.js") as $old) @unlink($old);
|
||||
$written = @file_put_contents("$base/v27-parse.spec.js", $spec);
|
||||
echo json_encode(["written" => $written]);
|
||||
7
api/ambre-pw-v28-deploy.php
Normal file
7
api/ambre-pw-v28-deploy.php
Normal file
@@ -0,0 +1,7 @@
|
||||
<?php
|
||||
header("Content-Type: application/json");
|
||||
$base = "/var/www/html/api/ambre-pw-tests/tests";
|
||||
$spec = base64_decode("Y29uc3QgeyB0ZXN0IH0gPSByZXF1aXJlKCJAcGxheXdyaWdodC90ZXN0Iik7Cgp0ZXN0KCJWMjggwrcgd3JhcCBmZXRjaCBhbmQgc2VuZCBISSIsIGFzeW5jICh7IHBhZ2UgfSkgPT4gewogIHRlc3Quc2V0VGltZW91dCg2MDAwMCk7CiAgCiAgY29uc3QgbmV0bG9nID0gW107CiAgY29uc3QgZXJycyA9IFtdOwogIHBhZ2Uub24oInBhZ2VlcnJvciIsIGUgPT4gZXJycy5wdXNoKGUubWVzc2FnZSkpOwogIHBhZ2Uub24oInJlc3BvbnNlIiwgcmVzID0+IHsKICAgIGlmIChyZXMudXJsKCkuaW5jbHVkZXMoIi9hcGkvIikpIHsKICAgICAgbmV0bG9nLnB1c2goeyB1cmw6IHJlcy51cmwoKS5zcGxpdCgiPyIpWzBdLCBzdGF0dXM6IHJlcy5zdGF0dXMoKSB9KTsKICAgIH0KICB9KTsKICAKICBhd2FpdCBwYWdlLmdvdG8oIi93ZXZpYS5odG1sIik7CiAgYXdhaXQgcGFnZS53YWl0Rm9yVGltZW91dCgyNTAwKTsKICAKICAvLyBNb25rZXktcGF0Y2ggZmV0Y2ggdG8gc2VlIGFsbCBjYWxscwogIGF3YWl0IHBhZ2UuZXZhbHVhdGUoKCkgPT4gewogICAgd2luZG93Ll9mZXRjaExvZyA9IFtdOwogICAgY29uc3Qgb3JpZyA9IHdpbmRvdy5mZXRjaDsKICAgIHdpbmRvdy5mZXRjaCA9IGZ1bmN0aW9uKHUsIG9wdHMpIHsKICAgICAgY29uc3QgdXJsID0gdHlwZW9mIHUgPT09ICJzdHJpbmciID8gdSA6IHUudXJsOwogICAgICB3aW5kb3cuX2ZldGNoTG9nLnB1c2goeyB1cmw6IHVybC5zcGxpdCgiPyIpWzBdLCBtZXRob2Q6IChvcHRzICYmIG9wdHMubWV0aG9kKSB8fCAiR0VUIiB9KTsKICAgICAgcmV0dXJuIG9yaWcuYXBwbHkodGhpcywgYXJndW1lbnRzKTsKICAgIH07CiAgfSk7CiAgCiAgLy8gU2VuZCAiSEkiCiAgYXdhaXQgcGFnZS5maWxsKCIjbXNnSW5wdXQiLCAiSEkiKTsKICBhd2FpdCBwYWdlLndhaXRGb3JUaW1lb3V0KDMwMCk7CiAgYXdhaXQgcGFnZS5wcmVzcygiI21zZ0lucHV0IiwgIkVudGVyIik7CiAgCiAgYXdhaXQgcGFnZS53YWl0Rm9yVGltZW91dCgxNTAwMCk7CiAgCiAgY29uc3QgZmV0Y2hMb2cgPSBhd2FpdCBwYWdlLmV2YWx1YXRlKCgpID0+IHdpbmRvdy5fZmV0Y2hMb2cpOwogIGNvbnNvbGUubG9nKCJcbj09PSBmZXRjaCBjYWxscyBmcm9tIEpTID09PSIpOwogIGNvbnNvbGUubG9nKEpTT04uc3RyaW5naWZ5KGZldGNoTG9nLCBudWxsLCAyKSk7CiAgCiAgY29uc29sZS5sb2coIlxuPT09IE5ldHdvcmsgbG9nICh2aWEgUGxheXdyaWdodCkgPT09Iik7CiAgY29uc29sZS5sb2coSlNPTi5zdHJpbmdpZnkobmV0bG9nLCBudWxsLCAyKSk7CiAgCiAgY29uc29sZS5sb2coIlxuPT09IFBhZ2UgZXJyb3JzID09PSIpOwogIGVycnMuZm9yRWFjaChlID0+IGNvbnNvbGUubG9nKCIgIiwgZS5zdWJzdHJpbmcoMCwgMjAwKSkpOwogIAogIC8vIERPTSBzdGF0ZQogIGNvbnN0IGRvbVN0YXRlID0gYXdhaXQgcGFnZS5ldmFsdWF0ZSgoKSA9PiB7CiAgICBjb25zdCBhID0gZG9jdW1lbnQucXVlcnlTZWxlY3RvckFsbCgiLm1zZy5hc3Npc3RhbnQgLmJ1YmJsZSIpOwogICAgcmV0dXJuIHsKICAgICAgY291bnQ6IGEubGVuZ3RoLAogICAgICBtZXNzYWdlczogQXJyYXkuZnJvbShhKS5tYXAoZWwgPT4gZWwuaW5uZXJUZXh0LnN1YnN0cmluZygwLCAyMDApKSwKICAgIH07CiAgfSk7CiAgY29uc29sZS5sb2coIlxuPT09IERPTSBtZXNzYWdlcyA9PT0iKTsKICBjb25zb2xlLmxvZyhKU09OLnN0cmluZ2lmeShkb21TdGF0ZSwgbnVsbCwgMikpOwp9KTsK");
|
||||
foreach (glob("$base/*.spec.js") as $old) @unlink($old);
|
||||
$written = @file_put_contents("$base/v28-fetch-log.spec.js", $spec);
|
||||
echo json_encode(["written" => $written]);
|
||||
43
api/ambre-wiki-pdf-scan.php
Normal file
43
api/ambre-wiki-pdf-scan.php
Normal file
@@ -0,0 +1,43 @@
|
||||
<?php
|
||||
header("Content-Type: application/json");
|
||||
$out = ["wiki_hits"=>[], "endpoints_pdf"=>[], "historic_pdf_mentions"=>[]];
|
||||
|
||||
// 1. Deep search obsidian vault
|
||||
$search_terms = ["pdf premium", "pdf graphique", "pdf chart", "chart.js pdf", "pdf artefact", "reportlab chart", "matplotlib pdf", "weasyprint chart"];
|
||||
foreach (glob("/opt/obsidian-vault/**/*.md") as $f) {
|
||||
$c = @file_get_contents($f);
|
||||
if (!$c) continue;
|
||||
foreach ($search_terms as $term) {
|
||||
if (stripos($c, $term) !== false) {
|
||||
$out["wiki_hits"][] = [
|
||||
"file" => str_replace("/opt/obsidian-vault/", "", $f),
|
||||
"term" => $term,
|
||||
"size" => strlen($c),
|
||||
"mtime" => date("Y-m-d", filemtime($f)),
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 2. All PDF-related endpoints
|
||||
foreach (glob("/var/www/html/api/*pdf*.php") as $f) {
|
||||
$out["endpoints_pdf"][] = ["name"=>basename($f), "size"=>filesize($f), "mtime"=>date("Y-m-d H:i", filemtime($f))];
|
||||
}
|
||||
foreach (glob("/var/www/html/api/*doc*.php") as $f) {
|
||||
$out["endpoints_pdf"][] = ["name"=>basename($f), "size"=>filesize($f), "mtime"=>date("Y-m-d H:i", filemtime($f))];
|
||||
}
|
||||
|
||||
// 3. Existing generated PDFs recent
|
||||
$gen_pdfs = [];
|
||||
foreach (glob("/var/www/html/generated/*.pdf") as $f) {
|
||||
$gen_pdfs[] = ["name"=>basename($f), "size_kb"=>round(filesize($f)/1024, 1), "mtime"=>date("Y-m-d H:i", filemtime($f))];
|
||||
}
|
||||
usort($gen_pdfs, function($a,$b){return strcmp($b["mtime"], $a["mtime"]);});
|
||||
$out["recent_pdfs"] = array_slice($gen_pdfs, 0, 5);
|
||||
|
||||
// 4. Look for any ambre-tool-pdf-premium.php current state
|
||||
$pdf_prem = "/var/www/html/api/ambre-tool-pdf-premium.php";
|
||||
$out["pdf_premium_exists"] = file_exists($pdf_prem);
|
||||
$out["pdf_premium_size"] = file_exists($pdf_prem) ? filesize($pdf_prem) : 0;
|
||||
|
||||
echo json_encode($out, JSON_PRETTY_PRINT|JSON_UNESCAPED_SLASHES);
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"generated_at": "2026-04-22T02:05:01.403657",
|
||||
"generated_at": "2026-04-22T02:10:01.412228",
|
||||
"stats": {
|
||||
"total": 48,
|
||||
"pending": 31,
|
||||
|
||||
133
api/growth-conversion-advisor.php
Normal file
133
api/growth-conversion-advisor.php
Normal file
@@ -0,0 +1,133 @@
|
||||
<?php
|
||||
// GROWTH ENGINE · Deep Conversion Advisor API · Wave 228
|
||||
// Retourne: matrice effort/impact, sovereign IA mapping, concurrence, top quick wins
|
||||
header('Content-Type: application/json; charset=utf-8');
|
||||
header('Access-Control-Allow-Origin: *');
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
$reg_path = __DIR__ . '/growth-engine-registry.json';
|
||||
$reg = is_file($reg_path) ? json_decode(file_get_contents($reg_path), true) : [];
|
||||
$assets = $reg['assets'] ?? [];
|
||||
|
||||
// Sovereign IA capabilities catalog (self-declared, live states)
|
||||
$sovereign = [
|
||||
['id'=>'wepredict','name'=>'WePredict','url'=>'/wepredict.html','category'=>'prediction',
|
||||
'capability'=>'16 cockpits · 64 predictions · load/churn/ops forecast','status'=>'live','maturity'=>85,
|
||||
'use_for_conversion'=>'Anticipate deal close probability, churn warning, upsell timing'],
|
||||
['id'=>'dark_scout','name'=>'Dark Scout V83','url'=>'/v83-dark-scout-enriched.html','category'=>'intel',
|
||||
'capability'=>'Dark web + clearnet monitoring · threat + opportunity detection','status'=>'live','maturity'=>78,
|
||||
'use_for_conversion'=>'Detect client mentions, competitor pricing, early intent signals'],
|
||||
['id'=>'wevia_master','name'=>'WEVIA Master','url'=>'/wevia-master.html','category'=>'orchestrator',
|
||||
'capability'=>'269 tools Dynamic Resolver · 13 intents Wave 200 · 7 exec Wave 201','status'=>'live','maturity'=>90,
|
||||
'use_for_conversion'=>'Orchestrate multi-agent replies to prospects, auto-propose solutions'],
|
||||
['id'=>'arena','name'=>'WEVAL Arena','url'=>'/weval-arena.html','category'=>'command-center',
|
||||
'capability'=>'409 options · 715 enterprise agents · multi-model benchmarking','status'=>'live','maturity'=>80,
|
||||
'use_for_conversion'=>'A/B test LLM outputs for client docs, choose best model per use case'],
|
||||
['id'=>'ethica_b2b','name'=>'Ethica B2B HCP','url'=>'/consent.wevup.app','category'=>'data',
|
||||
'capability'=>'157K HCPs · 87% email coverage · 34 specialties · 12 sources','status'=>'live','maturity'=>82,
|
||||
'use_for_conversion'=>'Pharma client prospecting, targeted campaigns MENA/EU/US'],
|
||||
['id'=>'wevads_brain','name'=>'WEVADS Brain','url'=>'/brain-tower.html','category'=>'email-engine',
|
||||
'capability'=>'646 configs · 9 winners · PMTA+Kumo+Postfix triple','status'=>'live','maturity'=>95,
|
||||
'use_for_conversion'=>'Cold outreach industrialized · 9 sacred winners · deliverability 95%+'],
|
||||
['id'=>'blade_ai','name'=>'Blade AI','url'=>'/blade-ai.html','category'=>'ai-agent',
|
||||
'capability'=>'Web agent · desktop automation · 232 task heartbeat','status'=>'live','maturity'=>75,
|
||||
'use_for_conversion'=>'Auto-fill proposals, demo prep, competitor research, account creation'],
|
||||
['id'=>'paperclip','name'=>'Paperclip PM','url'=>'/paperclip.html','category'=>'project-mgmt',
|
||||
'capability'=>'848 agents · 6 projects · 9 goals · task flow','status'=>'live','maturity'=>65,
|
||||
'use_for_conversion'=>'Deal progression tracking, delivery SLA monitoring'],
|
||||
['id'=>'oss_stack','name'=>'OSS Sovereign Stack','url'=>'/api/oss-manifest.php','category'=>'toolchain',
|
||||
'capability'=>'10 OSS installed · 1748 MB · pandasai+Ollama, WeasyPrint, BioPython, Selenium, DocuSeal','status'=>'live','maturity'=>85,
|
||||
'use_for_conversion'=>'Generate proposals (WeasyPrint+DocuSeal), analyze data (pandasai+LLM), automate UI (Selenium)'],
|
||||
];
|
||||
|
||||
// Effort/Impact matrix for top opportunities
|
||||
$opportunities = [
|
||||
['id'=>'vistex-cosumar','name'=>'Vistex SAP · Cosumar close','effort'=>3,'impact'=>9,'revenue_mad'=>450000,
|
||||
'status'=>'in_progress','time_days'=>14,'needs'=>['Lead addendum 0.8 DH/HCP counter','Portal demo'],
|
||||
'wevia_tools'=>['wevia_master','paperclip']],
|
||||
['id'=>'ethica-ma-contract','name'=>'Ethica Morocco · Kaouther Najar signing','effort'=>2,'impact'=>8,'revenue_mad'=>200000,
|
||||
'status'=>'in_progress','time_days'=>7,'needs'=>['Pilot consent ecm.py approval','Senders Arsenal'],
|
||||
'wevia_tools'=>['ethica_b2b','wevads_brain','wevia_master']],
|
||||
['id'=>'carrefour-retail','name'=>'Carrefour Morocco · CDC response','effort'=>5,'impact'=>8,'revenue_mad'=>350000,
|
||||
'status'=>'idea','time_days'=>21,'needs'=>['CDC specification','WeasyPrint proposal','Demo pharma+retail'],
|
||||
'wevia_tools'=>['oss_stack','wevia_master','paperclip']],
|
||||
['id'=>'api-hcp-package','name'=>'API HCP Maghreb · productize','effort'=>4,'impact'=>7,'revenue_mad'=>600000,
|
||||
'status'=>'in_progress','time_days'=>28,'needs'=>['Pricing tiers','Swagger docs','Stripe integration'],
|
||||
'wevia_tools'=>['ethica_b2b','arena']],
|
||||
['id'=>'weval-saas-freemium','name'=>'WEVAL SaaS Freemium launch','effort'=>6,'impact'=>9,'revenue_mad'=>800000,
|
||||
'status'=>'plan','time_days'=>45,'needs'=>['Landing','Stripe','Onboarding flow','FreePlan + Pro tier'],
|
||||
'wevia_tools'=>['wevia_master','blade_ai','oss_stack']],
|
||||
['id'=>'pharma-cloud-productize','name'=>'WEVAL Pharma Cloud productize','effort'=>5,'impact'=>8,'revenue_mad'=>500000,
|
||||
'status'=>'plan','time_days'=>30,'needs'=>['Package Ethica+WEVADS+Analytics','White-label','Partner channel'],
|
||||
'wevia_tools'=>['ethica_b2b','wevads_brain','wepredict']],
|
||||
['id'=>'linkedin-outbound','name'=>'LinkedIn outbound sequence','effort'=>1,'impact'=>5,'revenue_mad'=>80000,
|
||||
'status'=>'idea','time_days'=>3,'needs'=>['Selenium Blade sequencer','Copy 9 winners','Reply capture'],
|
||||
'wevia_tools'=>['blade_ai','wevads_brain']],
|
||||
['id'=>'stripe-consulting-pack','name'=>'Stripe Consulting pack Maghreb','effort'=>2,'impact'=>6,'revenue_mad'=>150000,
|
||||
'status'=>'idea','time_days'=>10,'needs'=>['Landing + calendly','Case studies','Stripe partner onboard'],
|
||||
'wevia_tools'=>['wevia_master']],
|
||||
['id'=>'seo-module-hub','name'=>'SEO Module Hub commercialization','effort'=>2,'impact'=>4,'revenue_mad'=>100000,
|
||||
'status'=>'plan','time_days'=>14,'needs'=>['Clients list','Pricing','Referral'],'wevia_tools'=>['paperclip']],
|
||||
['id'=>'huawei-refund','name'=>'Huawei Cloud refund (billing dispute)','effort'=>3,'impact'=>3,'revenue_mad'=>50000,
|
||||
'status'=>'in_progress','time_days'=>21,'needs'=>['Distributor switch','Docs'],'wevia_tools'=>['wevia_master']],
|
||||
];
|
||||
|
||||
// Competitor matrix
|
||||
$competitors = [
|
||||
['category'=>'SAP Consulting Maghreb','competitors'=>['Vistex','Valoris','Capgemini MA'],
|
||||
'weval_edge'=>'SAP Ecosystem Partner · AI-augmented · sovereign stack 0€ inference','threat'=>'medium'],
|
||||
['category'=>'Pharma HCP Data MENA','competitors'=>['IQVIA','Veeva','Doctolib Pro'],
|
||||
'weval_edge'=>'157K HCPs · consent-first WevUp · 87% email coverage sovereign','threat'=>'low'],
|
||||
['category'=>'E-signatures MENA','competitors'=>['DocuSign','Yousign','HelloSign'],
|
||||
'weval_edge'=>'DocuSeal self-hosted · 0€ · data sovereignty MENA','threat'=>'high'],
|
||||
['category'=>'Email deliverability','competitors'=>['Mailgun','Sendgrid','Mailjet'],
|
||||
'weval_edge'=>'PMTA+Kumo+Postfix triple · 95%+ deliverability · own IPs','threat'=>'medium'],
|
||||
['category'=>'AI orchestration SMB','competitors'=>['Make.com','Zapier','n8n cloud'],
|
||||
'weval_edge'=>'WEVIA Master sovereign · 626 tools · 17 providers cascade 0€','threat'=>'low'],
|
||||
];
|
||||
|
||||
// Focus & recommendations (effort/impact quadrants)
|
||||
$quick_wins = array_filter($opportunities, function($o){ return $o['effort']<=3 && $o['impact']>=7; });
|
||||
$big_bets = array_filter($opportunities, function($o){ return $o['effort']>=4 && $o['impact']>=7; });
|
||||
$fill_ins = array_filter($opportunities, function($o){ return $o['effort']<=3 && $o['impact']<7; });
|
||||
$thankless = array_filter($opportunities, function($o){ return $o['effort']>=4 && $o['impact']<7; });
|
||||
|
||||
$total_revenue_mad_quick = array_sum(array_map(function($o){return $o['revenue_mad'];}, $quick_wins));
|
||||
$total_revenue_mad_big = array_sum(array_map(function($o){return $o['revenue_mad'];}, $big_bets));
|
||||
|
||||
echo json_encode([
|
||||
'ts' => date('c'),
|
||||
'wave' => 228,
|
||||
'version' => 'deep-conversion-advisor-v1',
|
||||
'assets_count' => count($assets),
|
||||
'sovereign_ia' => $sovereign,
|
||||
'sovereign_ia_count' => count($sovereign),
|
||||
'opportunities' => array_values($opportunities),
|
||||
'matrix' => [
|
||||
'quick_wins' => array_values($quick_wins),
|
||||
'big_bets' => array_values($big_bets),
|
||||
'fill_ins' => array_values($fill_ins),
|
||||
'thankless' => array_values($thankless),
|
||||
],
|
||||
'matrix_revenue' => [
|
||||
'quick_wins_mad' => $total_revenue_mad_quick,
|
||||
'big_bets_mad' => $total_revenue_mad_big,
|
||||
],
|
||||
'competitors' => $competitors,
|
||||
'recommendations' => [
|
||||
[ 'rank'=>1, 'action'=>'Close Vistex Cosumar (7j)', 'why'=>'Quick win maximum · 450K MAD · need Yacine call Kaouther/Olga', 'deps'=>'Lead addendum 0.8 DH final answer'],
|
||||
[ 'rank'=>2, 'action'=>'Sign Ethica Morocco pilot (7j)', 'why'=>'Sovereign stack showcase · Kaouther Najar · 200K MAD', 'deps'=>'ecm.py pilot consent approval'],
|
||||
[ 'rank'=>3, 'action'=>'Launch LinkedIn outbound (3j)', 'why'=>'Low effort high cadence · Blade+WEVADS automation', 'deps'=>'Selenium sequencer + 9 winners copy'],
|
||||
[ 'rank'=>4, 'action'=>'Productize API HCP Maghreb (28j)', 'why'=>'600K MAD annual recurring · Stripe ready', 'deps'=>'Pricing tiers + Swagger public'],
|
||||
[ 'rank'=>5, 'action'=>'Launch WEVAL SaaS Freemium (45j)', 'why'=>'Big bet 800K MAD · showcase full stack', 'deps'=>'Landing + billing + onboarding'],
|
||||
],
|
||||
], JSON_UNESCAPED_UNICODE|JSON_PRETTY_PRINT);
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"ok": true,
|
||||
"version": "V83-business-kpi",
|
||||
"ts": "2026-04-22T00:04:42+00:00",
|
||||
"ts": "2026-04-22T00:09:16+00:00",
|
||||
"summary": {
|
||||
"total_categories": 8,
|
||||
"total_kpis": 64,
|
||||
|
||||
@@ -182,8 +182,8 @@ function buildKB(ops){
|
||||
|
||||
function build(){
|
||||
const nav=document.getElementById('nav');
|
||||
const tabLabels={dashboard:'Dashboard',pipeline:'Pipeline CRM',plan90:'Plan 90J',social:'Réseaux & Canaux',scout:'Dark Scout',predict:'WePredict',connections:'Connexions'};
|
||||
const tabColors={dashboard:'var(--gold)',pipeline:'var(--em)',plan90:'var(--am)',social:'var(--sa)',scout:'var(--cy)',predict:'var(--ro)',connections:'var(--vi)'};/*V86*/
|
||||
const tabLabels={dashboard:'Dashboard',advisor:'🎯 Conversion Advisor',pipeline:'Pipeline CRM',plan90:'Plan 90J',social:'Réseaux & Canaux',scout:'Dark Scout',predict:'WePredict',connections:'Connexions'};
|
||||
const tabColors={dashboard:'var(--gold)',advisor:'#22d3ee',pipeline:'var(--em)',plan90:'var(--am)',social:'var(--sa)',scout:'var(--cy)',predict:'var(--ro)',connections:'var(--vi)'};/*V86*/
|
||||
let nh='';
|
||||
TABS.forEach((t,i)=>{
|
||||
const on=i===0?' on':'';
|
||||
@@ -411,5 +411,131 @@ document.addEventListener('DOMContentLoaded',()=>{const s=document.createElement
|
||||
<script src="/api/a11y-auto-enhancer.js" defer></script>
|
||||
<!-- WTP_UDOCK_V1 (Opus 21-avr t32b4) --><script src="/wtp-unified-dock.js" defer></script>
|
||||
<script src="/opus-antioverlap-doctrine.js?v=1776776094" defer></script>
|
||||
|
||||
|
||||
<!-- WAVE 228 · Deep Conversion Advisor -->
|
||||
<script>
|
||||
(function(){
|
||||
if (window.__wevalAdvisorInit) return;
|
||||
window.__wevalAdvisorInit = true;
|
||||
|
||||
function renderAdvisor() {
|
||||
var content = document.getElementById('content') || document.querySelector('#content, .content, main, body > div');
|
||||
if (!content) return;
|
||||
content.innerHTML = '<div style="padding:24px"><div id="advisor-loading" style="color:#22d3ee">Loading Deep Conversion Advisor…</div><div id="advisor-content"></div></div>';
|
||||
fetch('/api/growth-conversion-advisor.php?cb='+Date.now())
|
||||
.then(function(r){return r.json();})
|
||||
.then(function(d){
|
||||
var loading = document.getElementById('advisor-loading');
|
||||
if (loading) loading.remove();
|
||||
var body = document.getElementById('advisor-content');
|
||||
if (body) body.innerHTML = buildAdvisor(d);
|
||||
})
|
||||
.catch(function(e){
|
||||
var body = document.getElementById('advisor-content');
|
||||
if (body) body.innerHTML = '<div style="color:#ef4444">Error: '+e.message+'</div>';
|
||||
});
|
||||
}
|
||||
|
||||
function oppRow(o, col) {
|
||||
var emoji = {in_progress:'🟡', plan:'🔵', idea:'💡'}[o.status] || '⚪';
|
||||
return '<div style="padding:6px 8px;margin-bottom:4px;background:rgba(0,0,0,.25);border-radius:4px;font-size:11px">'
|
||||
+ '<div style="display:flex;align-items:center;gap:6px;color:#e0e7ff">'
|
||||
+ emoji+' <b>'+o.name+'</b>'
|
||||
+ '<span style="margin-left:auto;color:'+col+';font-weight:700">'+Math.round(o.revenue_mad/1000)+'K MAD</span>'
|
||||
+ '</div>'
|
||||
+ '<div style="font-size:10px;color:#94a3b8;margin-top:2px">effort '+o.effort+'/10 · impact '+o.impact+'/10 · ~'+o.time_days+'j</div>'
|
||||
+ '</div>';
|
||||
}
|
||||
|
||||
function buildAdvisor(d) {
|
||||
var h = '<div style="display:flex;align-items:center;gap:12px;margin-bottom:20px;flex-wrap:wrap">';
|
||||
h += '<h2 style="margin:0;color:#22d3ee;font-size:20px;font-weight:700">🎯 Deep Conversion Advisor</h2>';
|
||||
h += '<span style="padding:4px 12px;border-radius:12px;background:linear-gradient(135deg,#22d3ee,#a855f7);color:#fff;font-size:10px;font-weight:800">WAVE 228</span>';
|
||||
h += '<span style="margin-left:auto;color:#94a3b8;font-size:12px">'+d.sovereign_ia_count+' IA souveraines · '+d.opportunities.length+' opportunités</span>';
|
||||
h += '</div>';
|
||||
|
||||
h += '<div style="display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:12px;margin-bottom:20px">';
|
||||
h += '<div style="padding:16px;background:linear-gradient(135deg,rgba(16,185,129,.15),rgba(16,185,129,.05));border:1px solid rgba(16,185,129,.3);border-radius:10px"><div style="font-size:11px;color:#6ee7b7;text-transform:uppercase;font-weight:700">Quick Wins</div><div style="font-size:28px;color:#10b981;font-weight:800">'+d.matrix.quick_wins.length+'</div><div style="font-size:13px;color:#6ee7b7">'+Math.round(d.matrix_revenue.quick_wins_mad/1000)+'K MAD · <14j</div></div>';
|
||||
h += '<div style="padding:16px;background:linear-gradient(135deg,rgba(168,85,247,.15),rgba(168,85,247,.05));border:1px solid rgba(168,85,247,.3);border-radius:10px"><div style="font-size:11px;color:#c4b5fd;text-transform:uppercase;font-weight:700">Big Bets</div><div style="font-size:28px;color:#a855f7;font-weight:800">'+d.matrix.big_bets.length+'</div><div style="font-size:13px;color:#c4b5fd">'+Math.round(d.matrix_revenue.big_bets_mad/1000)+'K MAD · 21-45j</div></div>';
|
||||
h += '<div style="padding:16px;background:linear-gradient(135deg,rgba(251,191,36,.15),rgba(251,191,36,.05));border:1px solid rgba(251,191,36,.3);border-radius:10px"><div style="font-size:11px;color:#fde68a;text-transform:uppercase;font-weight:700">Sovereign IA</div><div style="font-size:28px;color:#fbbf24;font-weight:800">'+d.sovereign_ia_count+'</div><div style="font-size:13px;color:#fde68a">WePredict · Dark Scout · Blade…</div></div>';
|
||||
h += '<div style="padding:16px;background:linear-gradient(135deg,rgba(236,72,153,.15),rgba(236,72,153,.05));border:1px solid rgba(236,72,153,.3);border-radius:10px"><div style="font-size:11px;color:#fbcfe8;text-transform:uppercase;font-weight:700">Competitors</div><div style="font-size:28px;color:#ec4899;font-weight:800">'+d.competitors.length+'</div><div style="font-size:13px;color:#fbcfe8">Categories mapped</div></div>';
|
||||
h += '</div>';
|
||||
|
||||
// TOP 5 recommendations
|
||||
h += '<div style="padding:18px;background:rgba(0,0,0,.35);border:1px solid rgba(34,211,238,.2);border-radius:10px;margin-bottom:20px">';
|
||||
h += '<div style="font-size:12px;color:#22d3ee;text-transform:uppercase;font-weight:700;margin-bottom:12px">🚀 TOP 5 actions prioritaires</div>';
|
||||
d.recommendations.forEach(function(r){
|
||||
h += '<div style="display:grid;grid-template-columns:40px 1fr;gap:10px;padding:10px;border-bottom:1px solid rgba(255,255,255,.04)">';
|
||||
h += '<div style="font-size:22px;font-weight:800;color:#22d3ee">#'+r.rank+'</div>';
|
||||
h += '<div><div style="font-size:14px;color:#e0f2fe;font-weight:600">'+r.action+'</div><div style="font-size:11.5px;color:#94a3b8;margin-top:3px">'+r.why+'</div><div style="font-size:10.5px;color:#64748b;margin-top:2px">🔗 '+r.deps+'</div></div>';
|
||||
h += '</div>';
|
||||
});
|
||||
h += '</div>';
|
||||
|
||||
// Matrix 2x2
|
||||
h += '<div style="padding:18px;background:rgba(0,0,0,.35);border:1px solid rgba(168,85,247,.2);border-radius:10px;margin-bottom:20px">';
|
||||
h += '<div style="font-size:12px;color:#a855f7;text-transform:uppercase;font-weight:700;margin-bottom:12px">📊 Matrice Effort × Impact</div>';
|
||||
h += '<div style="display:grid;grid-template-columns:1fr 1fr;gap:10px">';
|
||||
h += '<div style="padding:12px;background:rgba(16,185,129,.08);border:1px solid rgba(16,185,129,.25);border-radius:8px"><div style="font-size:11px;color:#6ee7b7;font-weight:700;margin-bottom:6px">✅ QUICK WINS · FAIS MAINTENANT</div>'+d.matrix.quick_wins.map(function(o){return oppRow(o,'#10b981');}).join('')+'</div>';
|
||||
h += '<div style="padding:12px;background:rgba(168,85,247,.08);border:1px solid rgba(168,85,247,.25);border-radius:8px"><div style="font-size:11px;color:#c4b5fd;font-weight:700;margin-bottom:6px">🎯 BIG BETS · PLANIFIE</div>'+d.matrix.big_bets.map(function(o){return oppRow(o,'#a855f7');}).join('')+'</div>';
|
||||
h += '<div style="padding:12px;background:rgba(251,191,36,.08);border:1px solid rgba(251,191,36,.25);border-radius:8px"><div style="font-size:11px;color:#fde68a;font-weight:700;margin-bottom:6px">💡 FILL-INS · DELEGUE</div>'+(d.matrix.fill_ins.length?d.matrix.fill_ins.map(function(o){return oppRow(o,'#fbbf24');}).join(''):'<div style="color:#94a3b8;font-size:11px">(aucune)</div>')+'</div>';
|
||||
h += '<div style="padding:12px;background:rgba(239,68,68,.08);border:1px solid rgba(239,68,68,.25);border-radius:8px"><div style="font-size:11px;color:#fca5a5;font-weight:700;margin-bottom:6px">⛔ THANKLESS · EVITE</div>'+(d.matrix.thankless.length?d.matrix.thankless.map(function(o){return oppRow(o,'#ef4444');}).join(''):'<div style="color:#94a3b8;font-size:11px">(aucune)</div>')+'</div>';
|
||||
h += '</div></div>';
|
||||
|
||||
// Sovereign IA
|
||||
h += '<div style="padding:18px;background:rgba(0,0,0,.35);border:1px solid rgba(251,191,36,.2);border-radius:10px;margin-bottom:20px">';
|
||||
h += '<div style="font-size:12px;color:#fbbf24;text-transform:uppercase;font-weight:700;margin-bottom:12px">🧠 '+d.sovereign_ia_count+' IA Souveraines · use for conversion</div>';
|
||||
h += '<div style="display:grid;grid-template-columns:repeat(auto-fit,minmax(260px,1fr));gap:10px">';
|
||||
d.sovereign_ia.forEach(function(s){
|
||||
h += '<div style="padding:12px;background:rgba(0,0,0,.25);border:1px solid rgba(251,191,36,.15);border-radius:8px">';
|
||||
h += '<div style="display:flex;align-items:center;gap:6px;margin-bottom:6px"><a href="'+s.url+'" target="_blank" style="color:#fde68a;font-weight:700;font-size:13px;text-decoration:none">'+s.name+' ↗</a><span style="margin-left:auto;padding:1px 6px;border-radius:8px;background:rgba(16,185,129,.2);color:#6ee7b7;font-size:9.5px;font-weight:700">'+s.status+'</span></div>';
|
||||
h += '<div style="font-size:10px;color:#94a3b8;text-transform:uppercase;margin-bottom:4px">'+s.category+'</div>';
|
||||
h += '<div style="font-size:11px;color:#fde68a;margin-bottom:6px">'+s.capability+'</div>';
|
||||
h += '<div style="font-size:11px;color:#10b981;padding:4px 6px;background:rgba(16,185,129,.05);border-radius:4px;border-left:2px solid #10b981">💡 '+s.use_for_conversion+'</div>';
|
||||
h += '<div style="margin-top:6px;height:4px;background:rgba(255,255,255,.04);border-radius:2px;overflow:hidden"><div style="height:100%;width:'+s.maturity+'%;background:linear-gradient(90deg,#fbbf24,#10b981)"></div></div>';
|
||||
h += '</div>';
|
||||
});
|
||||
h += '</div></div>';
|
||||
|
||||
// Competitors
|
||||
h += '<div style="padding:18px;background:rgba(0,0,0,.35);border:1px solid rgba(236,72,153,.2);border-radius:10px;margin-bottom:20px">';
|
||||
h += '<div style="font-size:12px;color:#ec4899;text-transform:uppercase;font-weight:700;margin-bottom:12px">🥊 Concurrence · WEVAL edge</div>';
|
||||
h += '<div style="display:flex;flex-direction:column;gap:8px">';
|
||||
d.competitors.forEach(function(c){
|
||||
var threatColor = {low:'#10b981', medium:'#fbbf24', high:'#ef4444'}[c.threat] || '#94a3b8';
|
||||
h += '<div style="padding:10px 12px;background:rgba(0,0,0,.2);border:1px solid rgba(236,72,153,.15);border-left:3px solid '+threatColor+';border-radius:6px">';
|
||||
h += '<div style="display:flex;align-items:center;gap:8px;flex-wrap:wrap"><b style="color:#fbcfe8;font-size:12.5px">'+c.category+'</b><span style="padding:1px 6px;border-radius:8px;background:'+threatColor+'22;color:'+threatColor+';font-size:9.5px;font-weight:700">threat: '+c.threat+'</span></div>';
|
||||
h += '<div style="font-size:11px;color:#94a3b8;margin-top:4px">vs: '+c.competitors.join(' · ')+'</div>';
|
||||
h += '<div style="font-size:11px;color:#6ee7b7;margin-top:4px">💪 <b>WEVAL edge:</b> '+c.weval_edge+'</div>';
|
||||
h += '</div>';
|
||||
});
|
||||
h += '</div></div>';
|
||||
|
||||
// Ask WEVIA prompts
|
||||
h += '<div style="padding:16px;background:linear-gradient(135deg,rgba(34,211,238,.08),rgba(168,85,247,.08));border:1px solid rgba(34,211,238,.25);border-radius:10px">';
|
||||
h += '<div style="font-size:12px;color:#22d3ee;font-weight:700;margin-bottom:8px">💬 Demande WEVIA Master d\'orchestrer</div>';
|
||||
h += '<div style="display:flex;flex-wrap:wrap;gap:6px">';
|
||||
var prompts = [
|
||||
['→ Plan 7j Vistex Cosumar','Plan 7 jours pour closer Vistex Cosumar: objections + contre-propositions + steps','#6ee7b7','rgba(16,185,129,.15)','rgba(16,185,129,.3)'],
|
||||
['→ Pricing API HCP','Pricing API HCP Maghreb 3 tiers + Stripe integration roadmap','#c4b5fd','rgba(168,85,247,.15)','rgba(168,85,247,.3)'],
|
||||
['→ LinkedIn outbound','Séquence LinkedIn outbound avec Blade+WEVADS 9 winners sur 20 prospects','#a5f3fc','rgba(34,211,238,.15)','rgba(34,211,238,.3)'],
|
||||
['→ Freemium plan','Plan lancement SaaS Freemium: landing + pricing + onboarding + 45j','#fde68a','rgba(251,191,36,.15)','rgba(251,191,36,.3)']
|
||||
];
|
||||
prompts.forEach(function(p){
|
||||
h += '<button onclick="var i=document.getElementById(\'cI\');if(i){i.value=\''+p[1].replace(/'/g,"\\'")+'\';i.focus();}" style="padding:6px 12px;border-radius:8px;background:'+p[3]+';color:'+p[2]+';border:1px solid '+p[4]+';font-size:11px;cursor:pointer;font-weight:600">'+p[0]+'</button>';
|
||||
});
|
||||
h += '</div></div>';
|
||||
|
||||
return h;
|
||||
}
|
||||
|
||||
document.addEventListener('click', function(e) {
|
||||
var target = e.target.closest && e.target.closest('[data-v="advisor"]');
|
||||
if (target) setTimeout(renderAdvisor, 200);
|
||||
});
|
||||
})();
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
Reference in New Issue
Block a user