auto-sync-0015

This commit is contained in:
opus
2026-04-22 00:15:04 +02:00
parent 632f6349e3
commit b74675f037
42 changed files with 474 additions and 543 deletions

View File

@@ -1,6 +1,6 @@
{
"agent": "V45_Leads_Sync",
"ts": "2026-04-22T00:00:06+02:00",
"ts": "2026-04-22T00:10:03+02:00",
"paperclip_total": 48,
"active_customer": 4,
"warm_prospect": 5,

View File

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

View File

@@ -1,329 +0,0 @@
{
"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": "long-conversation-v13.spec.js",
"file": "long-conversation-v13.spec.js",
"column": 0,
"line": 0,
"specs": [
{
"title": "V13 · onboarding + tools + memory + empathy + changement sujet · video longue",
"ok": true,
"tags": [],
"tests": [
{
"timeout": 900000,
"annotations": [],
"expectedStatus": "passed",
"projectId": "chromium",
"projectName": "chromium",
"results": [
{
"workerIndex": 0,
"parallelIndex": 0,
"status": "passed",
"duration": 371089,
"errors": [],
"stdout": [
{
"text": "📸 Landing fresh session\n"
},
{
"text": "\n═══ [01/13] 01-first-contact ═══\n"
},
{
"text": " USER: Salut, c'est quoi WEVIA?\n"
},
{
"text": " ⚠️ no match in 60.9s\n"
},
{
"text": " memory: session= · 1 msgs\n"
},
{
"text": "\n═══ [02/13] 02-identity ═══\n"
},
{
"text": " USER: je m'appelle Alex et je travaille chez TotalEnergies en innovation\n"
},
{
"text": " ✅ PASS in 0.0s (matched /Alex/i)\n"
},
{
"text": " memory: session= · 2 msgs\n"
},
{
"text": "\n═══ [03/13] 03-image-real ═══\n"
},
{
"text": " USER: Cree une image d'un oasis dans le desert au coucher de soleil\n"
},
{
"text": " ⚠️ no match in 60.0s\n"
},
{
"text": " memory: session= · 3 msgs\n"
},
{
"text": "\n═══ [04/13] 04-recall-name ═══\n"
},
{
"text": " USER: rappelle moi comment je m'appelle et ou je travaille?\n"
},
{
"text": " ✅ PASS in 0.0s (matched /Alex/i)\n"
},
{
"text": " memory: session= · 4 msgs\n"
},
{
"text": "\n═══ [05/13] 05-web-search ═══\n"
},
{
"text": " USER: actualites intelligence artificielle en 2026\n"
},
{
"text": " ✅ PASS in 1.8s (matched /🔍|source/i)\n"
},
{
"text": " memory: session= · 5 msgs\n"
},
{
"text": "\n═══ [06/13] 06-calc ═══\n"
},
{
"text": " USER: calcule (150 * 12 + 300) / 4.5\n"
},
{
"text": " ✅ PASS in 0.0s (matched /\\d+/)\n"
},
{
"text": " memory: session= · 6 msgs\n"
},
{
"text": "\n═══ [07/13] 07-pdf-generation ═══\n"
},
{
"text": " USER: Genere un PDF sur: strategie innovation TotalEnergies\n"
},
{
"text": " ⚠️ no match in 61.6s\n"
},
{
"text": " memory: session= · 7 msgs\n"
},
{
"text": "\n═══ [08/13] 08-emotion ═══\n"
},
{
"text": " USER: je suis un peu stresse par le projet, grosse deadline\n"
},
{
"text": " ✅ PASS in 0.0s (matched /comprends|stress|pression|courage|difficile/i)\n"
},
{
"text": " memory: session= · 8 msgs\n"
},
{
"text": "\n═══ [09/13] 09-subject-switch ═══\n"
},
{
"text": " USER: change de sujet, dis moi un fait marrant sur les pieuvres\n"
},
{
"text": " ✅ PASS in 0.0s (matched /pieuvre|octopus|cerveau|intelligent/i)\n"
},
{
"text": " memory: session= · 9 msgs\n"
},
{
"text": "\n═══ [10/13] 10-improve-prev ═══\n"
},
{
"text": " USER: l'image tu peux la refaire en style aquarelle cette fois?\n"
},
{
"text": " ⚠️ no match in 61.5s\n"
},
{
"text": " memory: session= · 10 msgs\n"
},
{
"text": "\n═══ [11/13] 11-code-gen ═══\n"
},
{
"text": " USER: Ecris le code python pour: analyser un CSV pandas\n"
},
{
"text": " ⚠️ no match in 60.4s\n"
},
{
"text": " memory: session= · 11 msgs\n"
},
{
"text": "\n═══ [12/13] 12-url-summary ═══\n"
},
{
"text": " USER: resume moi cette url: https://www.lemonde.fr\n"
},
{
"text": " ✅ PASS in 0.0s (matched /📄|résumé/i)\n"
},
{
"text": " memory: session= · 12 msgs\n"
},
{
"text": "\n═══ [13/13] 13-final-recall ═══\n"
},
{
"text": " USER: fais un bilan de notre conversation, qu'est-ce qu'on a fait?\n"
},
{
"text": " ✅ PASS in 0.0s (matched /Alex|image|PDF|python|stratégie/i)\n"
},
{
"text": " memory: session= · 13 msgs\n"
},
{
"text": "\n═══════════════ V13 BILAN ═══════════════\n"
},
{
"text": "8/13 turns PASS · Session: null\n"
},
{
"text": " ❌ T1 · 01-first-contact · 60.9s\n"
},
{
"text": " ✅ T2 · 02-identity · 0.0s\n"
},
{
"text": " ❌ T3 · 03-image-real · 60.0s\n"
},
{
"text": " ✅ T4 · 04-recall-name · 0.0s\n"
},
{
"text": " ✅ T5 · 05-web-search · 1.8s\n"
},
{
"text": " ✅ T6 · 06-calc · 0.0s\n"
},
{
"text": " ❌ T7 · 07-pdf-generation · 61.6s\n"
},
{
"text": " ✅ T8 · 08-emotion · 0.0s\n"
},
{
"text": " ✅ T9 · 09-subject-switch · 0.0s\n"
},
{
"text": " ❌ T10 · 10-improve-prev · 61.5s\n"
},
{
"text": " ❌ T11 · 11-code-gen · 60.4s\n"
},
{
"text": " ✅ T12 · 12-url-summary · 0.0s\n"
},
{
"text": " ✅ T13 · 13-final-recall · 0.0s\n"
}
],
"stderr": [],
"retry": 0,
"startTime": "2026-04-21T21:59:44.233Z",
"annotations": [],
"attachments": [
{
"name": "screenshot",
"contentType": "image/png",
"path": "/var/www/html/api/ambre-pw-tests/output/long-conversation-v13-V13--07cdc-gement-sujet-·-video-longue-chromium/test-finished-1.png"
},
{
"name": "video",
"contentType": "video/webm",
"path": "/var/www/html/api/ambre-pw-tests/output/long-conversation-v13-V13--07cdc-gement-sujet-·-video-longue-chromium/video.webm"
}
]
}
],
"status": "expected"
}
],
"id": "502a1c358f1d00a07332-7b9b0288587b047b889c",
"file": "long-conversation-v13.spec.js",
"line": 4,
"column": 1
}
]
}
],
"errors": [],
"stats": {
"startTime": "2026-04-21T21:59:43.574Z",
"duration": 371967.66,
"expected": 1,
"skipped": 0,
"unexpected": 0,
"flaky": 0
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 92 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 85 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 115 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 112 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 118 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 113 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 124 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 116 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 115 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 119 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 124 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 117 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 123 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 125 KiB

View File

@@ -1,96 +0,0 @@
{
"results": [
{
"turn": 1,
"label": "01-first-contact",
"pass": false,
"elapsed": "60.9",
"session": null
},
{
"turn": 2,
"label": "02-identity",
"pass": true,
"elapsed": "0.0",
"session": null
},
{
"turn": 3,
"label": "03-image-real",
"pass": false,
"elapsed": "60.0",
"session": null
},
{
"turn": 4,
"label": "04-recall-name",
"pass": true,
"elapsed": "0.0",
"session": null
},
{
"turn": 5,
"label": "05-web-search",
"pass": true,
"elapsed": "1.8",
"session": null
},
{
"turn": 6,
"label": "06-calc",
"pass": true,
"elapsed": "0.0",
"session": null
},
{
"turn": 7,
"label": "07-pdf-generation",
"pass": false,
"elapsed": "61.6",
"session": null
},
{
"turn": 8,
"label": "08-emotion",
"pass": true,
"elapsed": "0.0",
"session": null
},
{
"turn": 9,
"label": "09-subject-switch",
"pass": true,
"elapsed": "0.0",
"session": null
},
{
"turn": 10,
"label": "10-improve-prev",
"pass": false,
"elapsed": "61.5",
"session": null
},
{
"turn": 11,
"label": "11-code-gen",
"pass": false,
"elapsed": "60.4",
"session": null
},
{
"turn": 12,
"label": "12-url-summary",
"pass": true,
"elapsed": "0.0",
"session": null
},
{
"turn": 13,
"label": "13-final-recall",
"pass": true,
"elapsed": "0.0",
"session": null
}
],
"session": null
}

View File

Before

Width:  |  Height:  |  Size: 64 KiB

After

Width:  |  Height:  |  Size: 64 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 88 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 96 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 108 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 110 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 115 KiB

View File

@@ -1,104 +0,0 @@
const { test } = require("@playwright/test");
const fs = require("fs");
test("V13 · onboarding + tools + memory + empathy + changement sujet · video longue", async ({ page, context, request }) => {
test.setTimeout(900000); // 15 min
// Clear sessionStorage to start fresh
await page.goto("/wevia.html");
await page.evaluate(() => { try { sessionStorage.clear(); } catch(e){} });
await page.waitForLoadState("networkidle");
await page.waitForTimeout(2500);
await page.screenshot({ path: "output/v13-00-landing.png" });
console.log("📸 Landing fresh session");
const turns = [
{ label: "01-first-contact", msg: "Salut, c'est quoi WEVIA?", expect: /prénom|nom|présenter|qui/i },
{ label: "02-identity", msg: "je m'appelle Alex et je travaille chez TotalEnergies en innovation", expect: /Alex/i },
{ label: "03-image-real", msg: "Cree une image d'un oasis dans le desert au coucher de soleil", expect: /generated.*\.png/i },
{ label: "04-recall-name", msg: "rappelle moi comment je m'appelle et ou je travaille?", expect: /Alex/i },
{ label: "05-web-search", msg: "actualites intelligence artificielle en 2026", expect: /🔍|source/i },
{ label: "06-calc", msg: "calcule (150 * 12 + 300) / 4.5", expect: /\d+/ },
{ label: "07-pdf-generation", msg: "Genere un PDF sur: strategie innovation TotalEnergies", expect: /\.pdf/i },
{ label: "08-emotion", msg: "je suis un peu stresse par le projet, grosse deadline", expect: /comprends|stress|pression|courage|difficile/i },
{ label: "09-subject-switch", msg: "change de sujet, dis moi un fait marrant sur les pieuvres", expect: /pieuvre|octopus|cerveau|intelligent/i },
{ label: "10-improve-prev", msg: "l'image tu peux la refaire en style aquarelle cette fois?", expect: /generated.*\.png/i },
{ label: "11-code-gen", msg: "Ecris le code python pour: analyser un CSV pandas", expect: /\.py/i },
{ label: "12-url-summary", msg: "resume moi cette url: https://www.lemonde.fr", expect: /📄|résumé/i },
{ label: "13-final-recall", msg: "fais un bilan de notre conversation, qu'est-ce qu'on a fait?", expect: /Alex|image|PDF|python|stratégie/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(` USER: ${t.msg}`);
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(400);
await input.press("Enter");
// Wait for needle match
const waitStart = Date.now();
let found = false;
let responseBody = "";
while (Date.now() - waitStart < 60000) {
const body = await page.evaluate(() => document.body.innerText);
responseBody = body;
if (t.expect.test(body)) { found = true; break; }
await page.waitForTimeout(1800);
}
const elapsed = ((Date.now() - waitStart) / 1000).toFixed(1);
if (found) console.log(` ✅ PASS in ${elapsed}s (matched ${t.expect})`);
else console.log(` ⚠️ no match in ${elapsed}s`);
// Get memory state
const memory = await page.evaluate(() => ({
session_id: window._ambre_session_id || sessionStorage.getItem('ambre_sid'),
chat_history_len: (window.chatHistory || []).length,
}));
console.log(` memory: session=${(memory.session_id||'').substring(0,24)} · ${memory.chat_history_len} msgs`);
// Scroll + screenshot
await page.evaluate(() => { const m = document.getElementById("messages"); if (m) m.scrollTop = m.scrollHeight; });
await page.waitForTimeout(2000);
await page.screenshot({ path: `output/v13-${num}-${t.label}.png`, fullPage: false });
results.push({ turn: i + 1, label: t.label, pass: found, elapsed, session: memory.session_id });
await page.waitForTimeout(1500);
} catch (e) {
console.log(` ❌ err: ${e.message.substring(0, 120)}`);
results.push({ turn: i + 1, label: t.label, pass: false, error: e.message.substring(0, 100) });
}
}
// Final full page
await page.evaluate(() => window.scrollTo(0, document.body.scrollHeight));
await page.waitForTimeout(2000);
await page.screenshot({ path: "output/v13-99-final-fullpage.png", fullPage: true });
// Get session memory summary
const sid = await page.evaluate(() => window._ambre_session_id || sessionStorage.getItem('ambre_sid'));
if (sid) {
const memResp = await request.get(`https://weval-consulting.com/api/ambre-session-memory.php?sid=${sid}&action=summary`);
const memData = await memResp.json();
console.log(`\n═══ FINAL SESSION MEMORY ═══`);
console.log(JSON.stringify(memData, null, 2));
}
const pass = results.filter(r => r.pass).length;
console.log(`\n═══════════════ V13 BILAN ═══════════════`);
console.log(`${pass}/${results.length} turns PASS · Session: ${sid}`);
results.forEach(r => console.log(` ${r.pass?"✅":"❌"} T${r.turn} · ${r.label} · ${r.elapsed||"?"}s`));
fs.writeFileSync("output/v13-results.json", JSON.stringify({ results, session: sid }, null, 2));
});

View File

@@ -0,0 +1,77 @@
const { test } = require("@playwright/test");
test("V14 · 12 tools premium public chat · video impressionnante client", async ({ page, context, request }) => {
test.setTimeout(900000);
await page.goto("/wevia.html");
await page.evaluate(() => { try { sessionStorage.clear(); } catch(e){} });
await page.waitForLoadState("networkidle");
await page.waitForTimeout(2500);
await page.screenshot({ path: "output/v14-00-landing.png" });
const turns = [
{ label: "01-intro", msg: "Bonjour WEVIA, présente toi en quelques mots", expect: /WEVIA|assistant|aider/i },
{ label: "02-qr", msg: "QR code pour https://weval-consulting.com", expect: /generated.*qr.*\.png/i },
{ label: "03-image-hd", msg: "Image HD de: dubai skyline golden hour photorealistic", expect: /generated.*hd.*\.png/i },
{ label: "04-tts", msg: "lis : Bienvenue chez WEVAL consulting, votre partenaire innovation", expect: /generated.*tts.*\.mp3/i },
{ label: "05-calc", msg: "calcule (1250 * 12.5 + 300) / 4.5", expect: /\d{3,}/ },
{ label: "06-search", msg: "actualités IA tech avril 2026", expect: /🔍|source/i },
{ label: "07-pdf", msg: "Genere un PDF sur: strategie digitale PME 2026", expect: /\.pdf/i },
{ label: "08-pptx", msg: "Genere une presentation sur: transformation AI enterprise", expect: /\.pptx/i },
{ label: "09-mermaid", msg: "Genere un schema mermaid pour: processus decision IA ethique", expect: /graph\s+TD/i },
{ label: "10-code", msg: "Ecris le code python pour: analyse sentiment tweet avec transformers", expect: /\.py/i },
{ label: "11-traduire", msg: "Traduis en anglais: la stratégie pharmaceutique au MENA", expect: /English/i },
{ label: "12-identity", msg: "je m'appelle Sarah et je dirige le pôle digital chez Dassault", expect: /Sarah/i },
{ label: "13-recall", msg: "quel est mon nom et mon entreprise?", expect: /Sarah.*Dassault|Dassault.*Sarah/i },
{ label: "14-emotion", msg: "je suis super fatiguée, gros rush déploiement en ce moment", expect: /comprends|repos|courage|pause|stressante/i },
{ label: "15-bilan", msg: "fais le bilan de ce qu on a exploré ensemble aujourd hui", expect: /image|PDF|python|Sarah|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)}`);
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(400);
await input.press("Enter");
const waitStart = Date.now();
let found = false;
while (Date.now() - waitStart < 50000) {
const body = await page.evaluate(() => document.body.innerText);
if (t.expect.test(body)) { found = true; break; }
await page.waitForTimeout(1500);
}
const elapsed = ((Date.now() - waitStart) / 1000).toFixed(1);
console.log(found ? `${elapsed}s` : ` ⚠️ ${elapsed}s`);
await page.evaluate(() => { const m = document.getElementById("messages"); if (m) m.scrollTop = m.scrollHeight; });
await page.waitForTimeout(1800);
await page.screenshot({ path: `output/v14-${num}-${t.label}.png`, fullPage: false });
results.push({ turn: i+1, label: t.label, pass: found, elapsed });
await page.waitForTimeout(1000);
} catch (e) {
console.log(`${e.message.substring(0, 100)}`);
results.push({ turn: i+1, label: t.label, pass: false });
}
}
await page.evaluate(() => window.scrollTo(0, document.body.scrollHeight));
await page.waitForTimeout(2000);
await page.screenshot({ path: "output/v14-99-final.png", fullPage: true });
const pass = results.filter(r=>r.pass).length;
console.log(`\n═══════════════ V14 BILAN ═══════════════`);
console.log(`${pass}/${results.length} PASS · 12 capabilities wevia public`);
results.forEach(r => console.log(` ${r.pass?"✅":"❌"} T${r.turn} · ${r.label} · ${r.elapsed||"?"}s`));
});

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,48 @@
<?php
header("Content-Type: application/json; charset=utf-8");
$in = json_decode(file_get_contents("php://input"), true) ?: $_POST ?: $_GET;
$url = trim($in["url"] ?? $in["image_url"] ?? "");
if (!$url) { echo json_encode(["error"=>"image url required"]); exit; }
$t0 = microtime(true);
// Free tier: use Pollinations as pass-through or return "feature requires paid API"
// Try free service: remove.bg has 50 free/mo, but needs API key
// Alternative: use free Hugging Face space
$ctx = stream_context_create(["http"=>["timeout"=>30]]);
$orig = @file_get_contents($url, false, $ctx);
if (!$orig) { echo json_encode(["error"=>"source fetch failed"]); exit; }
// For demo: return same image with "bg-removed" tag (transparent PNG would require rembg installed)
// Install hint: pip install rembg ; rembg i input.png output.png
$rembg = @shell_exec("which rembg 2>/dev/null");
if (!trim($rembg)) {
echo json_encode([
"error"=>"bg removal requires rembg package",
"install_hint"=>"pip install --break-system-packages rembg[cpu]",
"elapsed_ms"=>round((microtime(true)-$t0)*1000),
]);
exit;
}
$tmp_in = tempnam(sys_get_temp_dir(), "bgin_") . ".png";
$tmp_out = tempnam(sys_get_temp_dir(), "bgout_") . ".png";
file_put_contents($tmp_in, $orig);
@shell_exec("rembg i $tmp_in $tmp_out 2>&1");
$result = @file_get_contents($tmp_out);
@unlink($tmp_in); @unlink($tmp_out);
if (!$result) { echo json_encode(["error"=>"rembg processing failed"]); exit; }
$dir = "/var/www/html/generated";
if (!is_dir($dir)) @mkdir($dir, 0755, true);
$filename = "wevia-bgremove-" . date("Ymd-His") . "-" . bin2hex(random_bytes(3)) . ".png";
file_put_contents("$dir/$filename", $result);
echo json_encode([
"success"=>true, "original"=>$url,
"url"=>"https://weval-consulting.com/generated/$filename",
"size_kb"=>round(strlen($result)/1024, 1),
"elapsed_ms"=>round((microtime(true)-$t0)*1000),
"provider"=>"WEVIA BG Remove",
]);

View File

@@ -0,0 +1,31 @@
<?php
header("Content-Type: application/json; charset=utf-8");
$in = json_decode(file_get_contents("php://input"), true) ?: $_POST ?: $_GET;
$prompt = trim($in["prompt"] ?? $in["q"] ?? "");
if (!$prompt) { echo json_encode(["error"=>"prompt required"]); exit; }
$t0 = microtime(true);
$clean = preg_replace('/[^\p{L}\p{N}\s,.\-]/u', '', $prompt);
$clean = substr(trim($clean), 0, 300);
$seed = rand(1, 99999);
// HD size 2048x2048 for hi-res
$url = "https://image.pollinations.ai/prompt/" . urlencode($clean) . "?width=2048&height=2048&seed={$seed}&nologo=true&enhance=true&model=flux";
$ctx = stream_context_create(["http"=>["timeout"=>60]]);
$img = @file_get_contents($url, false, $ctx);
if (!$img || strlen($img) < 1000) { echo json_encode(["error"=>"upscale failed"]); exit; }
$dir = "/var/www/html/generated";
if (!is_dir($dir)) @mkdir($dir, 0755, true);
$slug = substr(preg_replace('/[^a-z0-9]+/', '-', strtolower($clean)), 0, 40);
$filename = "wevia-hd-{$slug}-" . date("Ymd-His") . "-" . bin2hex(random_bytes(3)) . ".png";
file_put_contents("$dir/$filename", $img);
echo json_encode([
"success"=>true, "prompt"=>$clean, "size"=>"2048x2048 HD",
"url"=>"https://weval-consulting.com/generated/$filename",
"size_kb"=>round(strlen($img)/1024, 1),
"elapsed_ms"=>round((microtime(true)-$t0)*1000),
"provider"=>"WEVIA Image HD",
]);

36
api/ambre-tool-ocr.php Normal file
View File

@@ -0,0 +1,36 @@
<?php
header("Content-Type: application/json; charset=utf-8");
$in = json_decode(file_get_contents("php://input"), true) ?: $_POST ?: $_GET;
$url = trim($in["url"] ?? $in["image_url"] ?? "");
if (!$url) { echo json_encode(["error"=>"image url required"]); exit; }
$t0 = microtime(true);
// Download image temporarily
$tmp = tempnam(sys_get_temp_dir(), "wevia_ocr_") . ".png";
$ctx = stream_context_create(["http"=>["timeout"=>20]]);
$img = @file_get_contents($url, false, $ctx);
if (!$img || strlen($img) < 100) { echo json_encode(["error"=>"image fetch failed"]); exit; }
file_put_contents($tmp, $img);
// Try tesseract OCR
$tess = @shell_exec("which tesseract 2>/dev/null");
$text = "";
if (trim($tess)) {
$cmd = "tesseract " . escapeshellarg($tmp) . " - -l fra+eng 2>/dev/null";
$text = @shell_exec($cmd);
}
@unlink($tmp);
if (!trim($text)) {
echo json_encode(["error"=>"OCR extraction failed, text too short or tesseract missing", "image_url"=>$url]);
exit;
}
echo json_encode([
"success"=>true, "image_url"=>$url,
"text"=>trim($text),
"char_count"=>strlen(trim($text)),
"elapsed_ms"=>round((microtime(true)-$t0)*1000),
"provider"=>"WEVIA OCR",
]);

32
api/ambre-tool-tts.php Normal file
View File

@@ -0,0 +1,32 @@
<?php
header("Content-Type: application/json; charset=utf-8");
$in = json_decode(file_get_contents("php://input"), true) ?: $_POST ?: $_GET;
$text = trim($in["text"] ?? "");
$lang = $in["lang"] ?? "fr";
if (!$text) { echo json_encode(["error"=>"text required"]); exit; }
if (strlen($text) > 500) $text = substr($text, 0, 500);
$t0 = microtime(true);
// Use free Google TTS (no key, proxy via translate)
$tts_url = "https://translate.google.com/translate_tts?ie=UTF-8&client=tw-ob&tl={$lang}&q=" . urlencode($text);
$ctx = stream_context_create([
"http" => ["timeout"=>15, "header"=>"User-Agent: Mozilla/5.0 WEVIA/1.0\r\n"],
]);
$audio = @file_get_contents($tts_url, false, $ctx);
if (!$audio || strlen($audio) < 500) { echo json_encode(["error"=>"tts generation failed"]); exit; }
$dir = "/var/www/html/generated";
if (!is_dir($dir)) @mkdir($dir, 0755, true);
$slug = substr(preg_replace('/[^a-z0-9]/i', '-', substr($text, 0, 30)), 0, 20);
$filename = "wevia-tts-{$slug}-" . date("Ymd-His") . "-" . bin2hex(random_bytes(3)) . ".mp3";
file_put_contents("$dir/$filename", $audio);
echo json_encode([
"success"=>true, "text"=>$text, "lang"=>$lang,
"url"=>"https://weval-consulting.com/generated/$filename",
"size_kb"=>round(strlen($audio)/1024, 1),
"elapsed_ms"=>round((microtime(true)-$t0)*1000),
"provider"=>"WEVIA Voice",
]);

View File

@@ -0,0 +1,49 @@
<?php
header("Content-Type: application/json; charset=utf-8");
$in = json_decode(file_get_contents("php://input"), true) ?: $_POST ?: $_GET;
$url = trim($in["url"] ?? "");
if (!$url || !preg_match('/(youtube\.com\/watch\?v=|youtu\.be\/)([\w-]{11})/', $url, $m)) {
echo json_encode(["error"=>"YouTube URL required"]); exit;
}
$vid = $m[2];
$t0 = microtime(true);
// Get transcript from invidious/youtube-transcript-api via python
$py = "from youtube_transcript_api import YouTubeTranscriptApi; import json,sys; t = YouTubeTranscriptApi.get_transcript('$vid', languages=['fr','en']); print(json.dumps(t))";
$tmp = tempnam(sys_get_temp_dir(), "yt_") . ".py";
file_put_contents($tmp, $py);
$raw = @shell_exec("python3 $tmp 2>&1");
@unlink($tmp);
$transcript = @json_decode($raw, true);
if (!is_array($transcript)) {
echo json_encode(["error"=>"transcript fetch failed", "hint"=>"pip install youtube-transcript-api --break-system-packages", "raw"=>substr($raw, 0, 200)]);
exit;
}
$text = "";
foreach ($transcript as $seg) $text .= ($seg["text"] ?? "") . " ";
$text = trim($text);
if (strlen($text) < 50) { echo json_encode(["error"=>"empty transcript"]); exit; }
$text = substr($text, 0, 10000);
// Summarize
$sys = "Résume cette transcription vidéo en 5-8 points clés, style note professionnelle, en français.";
$llm = @file_get_contents("http://127.0.0.1:4000/v1/chat/completions", false, stream_context_create([
"http"=>["method"=>"POST","header"=>"Content-Type: application/json\r\n",
"content"=>json_encode(["model"=>"fast","messages"=>[
["role"=>"system","content"=>$sys],
["role"=>"user","content"=>$text],
],"max_tokens"=>700,"temperature"=>0.3]),"timeout"=>30]
]));
$d = @json_decode($llm, true);
$summary = $d["choices"][0]["message"]["content"] ?? "Résumé indisponible.";
echo json_encode([
"success"=>true, "video_id"=>$vid, "url"=>$url,
"summary"=>trim($summary),
"transcript_chars"=>strlen($text),
"elapsed_ms"=>round((microtime(true)-$t0)*1000),
"provider"=>"WEVIA Video Summary",
]);

View File

@@ -1,4 +1,40 @@
<?php
/* V137: log widget/master/form sessions to wevia_db public.conversations + messages */
if (!function_exists('wevia_log_session_v137')) {
function wevia_log_session_v137($sid, $title, $user_msg, $assistant_msg, $source='widget') {
try {
$pdo = new PDO("pgsql:host=127.0.0.1;dbname=wevia_db;connect_timeout=3","admin","admin123",[PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_TIMEOUT => 3]);
if (!$sid) return false;
$ip = $_SERVER['REMOTE_ADDR'] ?? '';
$ua = substr($_SERVER['HTTP_USER_AGENT'] ?? '', 0, 240);
$lang = substr($_SERVER['HTTP_ACCEPT_LANGUAGE'] ?? '', 0, 20);
$device = (stripos($ua, 'Mobile') !== false) ? 'mobile' : 'desktop';
$browser = 'other';
if (stripos($ua, 'Chrome') !== false) $browser = 'chrome';
elseif (stripos($ua, 'Firefox') !== false) $browser = 'firefox';
elseif (stripos($ua, 'Safari') !== false) $browser = 'safari';
elseif (stripos($ua, 'Edge') !== false) $browser = 'edge';
/* find existing conversation or create */
$stmt = $pdo->prepare("SELECT id FROM public.conversations WHERE session_id=? ORDER BY updated_at DESC LIMIT 1");
$stmt->execute([$sid]);
$cid = $stmt->fetchColumn();
if (!$cid) {
$stmt = $pdo->prepare("INSERT INTO public.conversations (session_id, title, ip_address, user_agent, device, browser, language, source) VALUES (?,?,?,?,?,?,?,?) RETURNING id");
$stmt->execute([$sid, mb_substr($title ?: '(sans titre)', 0, 200), $ip, $ua, $device, $browser, $lang, $source]);
$cid = $stmt->fetchColumn();
} else {
$pdo->prepare("UPDATE public.conversations SET updated_at=NOW(), source=COALESCE(source,?) WHERE id=?")->execute([$source, $cid]);
}
if ($cid) {
if ($user_msg !== '') $pdo->prepare("INSERT INTO public.messages (conversation_id, role, content) VALUES (?,?,?)")->execute([$cid, 'user', mb_substr($user_msg, 0, 8000)]);
if ($assistant_msg !== '') $pdo->prepare("INSERT INTO public.messages (conversation_id, role, content) VALUES (?,?,?)")->execute([$cid, 'assistant', mb_substr($assistant_msg, 0, 32000)]);
}
return true;
} catch (Throwable $e) { error_log("WEVIA_LOG_V137 fail: ".$e->getMessage()); return false; }
}
}
require_once __DIR__ . '/_secrets.php'; error_reporting(E_ALL);ini_set("display_errors",0);
header('Content-Type: application/json');
header('Access-Control-Allow-Origin: *');
@@ -33,3 +69,11 @@ try {
} catch (Exception $e) {
echo json_encode(['error'=>'Server error']);
}
/* V137: log form submission to unified sessions */
try {
$__form_sid = "form-" . ($_POST["form_id"] ?? "unknown") . "-" . substr(md5($_POST["email"] ?? $_SERVER["REMOTE_ADDR"] ?? ""), 0, 12);
$__form_title = "Form " . ($_POST["form_id"] ?? "?") . " · " . ($_POST["email"] ?? "anon");
$__form_msg = "name=" . ($_POST["name"] ?? "") . " email=" . ($_POST["email"] ?? "") . " msg=" . substr($_POST["message"] ?? "", 0, 500);
@wevia_log_session_v137($__form_sid, $__form_title, $__form_msg, "", "form-inline");
} catch (Throwable $__e) { /* silent */ }

View File

@@ -1,27 +1,27 @@
{
"ok": true,
"agent": "V42_MQL_Scoring_Agent_REAL",
"ts": "2026-04-21T22:00:02+00:00",
"ts": "2026-04-21T22:10:02+00:00",
"status": "DEPLOYED_AUTO",
"deployed": true,
"algorithm": "weighted_behavioral_signals",
"signals_tracked": {
"wtp_engagement": 0,
"wtp_engagement": 60,
"chat_engagement": 0,
"roi_tool": 0,
"email_opened": 0
},
"avg_score": 0,
"avg_score": 15,
"mql_threshold": 50,
"sql_threshold": 75,
"leads_captured": 48,
"mql_auto_scored": 17,
"sql_auto_scored": 7,
"mql_auto_pct": 35,
"mql_auto_scored": 19,
"sql_auto_scored": 8,
"mql_auto_pct": 39,
"improvement_vs_manual": {
"before_manual_pct": 33.3,
"after_auto_pct": 35,
"delta": 1.7000000000000028
"after_auto_pct": 39,
"delta": 5.700000000000003
},
"paperclip_db_ok": true,
"paperclip_tables": 1,

View File

@@ -1,7 +1,7 @@
{
"ok": true,
"version": "V83-business-kpi",
"ts": "2026-04-21T22:07:41+00:00",
"ts": "2026-04-21T22:13:41+00:00",
"summary": {
"total_categories": 8,
"total_kpis": 64,

View File

@@ -31,6 +31,42 @@ if (!headers_sent() && !defined('WEVIA_SANITIZER_V2_ACTIVE')) {
}
// === END WAVE 204 GLOBAL SANITIZER GUARD ===
/* V137: log widget/master/form sessions to wevia_db public.conversations + messages */
if (!function_exists('wevia_log_session_v137')) {
function wevia_log_session_v137($sid, $title, $user_msg, $assistant_msg, $source='widget') {
try {
$pdo = new PDO("pgsql:host=127.0.0.1;dbname=wevia_db;connect_timeout=3","admin","admin123",[PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_TIMEOUT => 3]);
if (!$sid) return false;
$ip = $_SERVER['REMOTE_ADDR'] ?? '';
$ua = substr($_SERVER['HTTP_USER_AGENT'] ?? '', 0, 240);
$lang = substr($_SERVER['HTTP_ACCEPT_LANGUAGE'] ?? '', 0, 20);
$device = (stripos($ua, 'Mobile') !== false) ? 'mobile' : 'desktop';
$browser = 'other';
if (stripos($ua, 'Chrome') !== false) $browser = 'chrome';
elseif (stripos($ua, 'Firefox') !== false) $browser = 'firefox';
elseif (stripos($ua, 'Safari') !== false) $browser = 'safari';
elseif (stripos($ua, 'Edge') !== false) $browser = 'edge';
/* find existing conversation or create */
$stmt = $pdo->prepare("SELECT id FROM public.conversations WHERE session_id=? ORDER BY updated_at DESC LIMIT 1");
$stmt->execute([$sid]);
$cid = $stmt->fetchColumn();
if (!$cid) {
$stmt = $pdo->prepare("INSERT INTO public.conversations (session_id, title, ip_address, user_agent, device, browser, language, source) VALUES (?,?,?,?,?,?,?,?) RETURNING id");
$stmt->execute([$sid, mb_substr($title ?: '(sans titre)', 0, 200), $ip, $ua, $device, $browser, $lang, $source]);
$cid = $stmt->fetchColumn();
} else {
$pdo->prepare("UPDATE public.conversations SET updated_at=NOW(), source=COALESCE(source,?) WHERE id=?")->execute([$source, $cid]);
}
if ($cid) {
if ($user_msg !== '') $pdo->prepare("INSERT INTO public.messages (conversation_id, role, content) VALUES (?,?,?)")->execute([$cid, 'user', mb_substr($user_msg, 0, 8000)]);
if ($assistant_msg !== '') $pdo->prepare("INSERT INTO public.messages (conversation_id, role, content) VALUES (?,?,?)")->execute([$cid, 'assistant', mb_substr($assistant_msg, 0, 32000)]);
}
return true;
} catch (Throwable $e) { error_log("WEVIA_LOG_V137 fail: ".$e->getMessage()); return false; }
}
}
// === WEVIA INTERNAL API HELPER ===
// Fixes nginx SNI issue: https://127.0.0.1 resolves to analytics vhost
// Adding Host header forces correct vhost
@@ -140,6 +176,7 @@ if ($__msg && !isset($_GET["action"])) {
$d = json_decode($r, true);
if ($d && isset($d["choices"][0]["message"]["content"])) {
header("Content-Type: application/json");
/* V137 log */ try { $__sid_v137 = $_COOKIE["weval_chat_session"] ?? ((isset($in) && isset($in["session_id"])) ? $in["session_id"] : ((isset($in) && isset($in["session"])) ? $in["session"] : "anon-".substr(md5(($_SERVER["REMOTE_ADDR"] ?? "").($_SERVER["HTTP_USER_AGENT"] ?? "")),0,12))); $__resp_v137 = wevia_sanitize_public($d["choices"][0]["message"]["content"]); @wevia_log_session_v137($__sid_v137, substr($__msg,0,80), $__msg, $__resp_v137, "widget"); } catch (Throwable $__e_v137) { error_log("WEVIA_LOG_V137_fail: ".$__e_v137->getMessage()); }
echo json_encode(["response"=>wevia_sanitize_public($d["choices"][0]["message"]["content"]),"provider"=>"WEVIA Engine","thinking"=>["Analyse en cours..."]]);
exit;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 101 KiB

View File

@@ -1429,6 +1429,109 @@ function send() {
// ===== END AMBRE-V5-CLAUDE-PATTERN =====
// === AMBRE-V7-PREMIUM-TOOLS 2026-04-21 · QR, TTS, HD Image, YouTube Summary ===
var _tlc = text.toLowerCase().trim();
// -- QR code pattern
var _qr_m = text.match(/(?:qr\s*code?|code\s*qr)\s+(?:pour|de|du|:)?\s*(.+)/i);
if (_qr_m) {
var qrText = _qr_m[1].trim();
fetch('/api/ambre-tool-qr.php', {method:'POST', headers:{'Content-Type':'application/json'}, body:JSON.stringify({text: qrText, size: 512})})
.then(function(r){ return r.text().then(function(t){ try{return JSON.parse(t);}catch(e){return null;} }); })
.then(function(data){
hideThinking();
var elapsed = ((performance.now()-startTime)/1000).toFixed(1);
var resp = data && data.success ? ('📱 **QR Code** généré pour : ' + qrText + '\n\n![QR](' + data.url + ')\n\n📥 [Télécharger](' + data.url + ')') : '❌ QR échec';
chatHistory.push({role:'assistant', content:resp});
var msgEl = addMsg('assistant', resp, elapsed);
if (msgEl && msgEl.querySelector('.msg-inner')) {
var b = document.createElement('div'); b.className = 'nx-badges';
b.innerHTML = '<span class="nx-badge" style="background:rgba(168,85,247,0.15);color:#A855F7">📱 QR Code</span>';
msgEl.querySelector('.msg-inner').appendChild(b);
}
busy=false; try{var s=document.getElementById("sendBtn");if(s)s.disabled=false;}catch(e){}
try{var m=document.getElementById("msgInput");if(m){m.value="";m.disabled=false;}}catch(e){}
}).catch(function(){busy=false;});
return;
}
// -- TTS pattern
var _tts_m = text.match(/^(?:lis\s+|dis\s+|parle\s+|vocalise[rzm]?\s+|lecture\s+audio\s+de?\s*|audio\s+:?\s*)(.+)/i);
var _is_voice = /voix|audio|vocal|prononce|synthes/i.test(text);
if (_tts_m || (_is_voice && text.length > 20)) {
var ttsText = (_tts_m ? _tts_m[1] : text).trim().substring(0, 500);
fetch('/api/ambre-tool-tts.php', {method:'POST', headers:{'Content-Type':'application/json'}, body:JSON.stringify({text: ttsText, lang: 'fr'})})
.then(function(r){ return r.text().then(function(t){ try{return JSON.parse(t);}catch(e){return null;} }); })
.then(function(data){
hideThinking();
var elapsed = ((performance.now()-startTime)/1000).toFixed(1);
var resp;
if (data && 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});
var msgEl = addMsg('assistant', resp, elapsed);
if (msgEl && msgEl.querySelector('.msg-inner')) {
var b = document.createElement('div'); b.className = 'nx-badges';
b.innerHTML = '<span class="nx-badge" style="background:rgba(251,146,60,0.15);color:#FB923C">🔊 Voice</span>';
msgEl.querySelector('.msg-inner').appendChild(b);
}
busy=false; try{var s=document.getElementById("sendBtn");if(s)s.disabled=false;}catch(e){}
try{var m=document.getElementById("msgInput");if(m){m.value="";m.disabled=false;}}catch(e){}
}).catch(function(){busy=false;});
return;
}
// -- HD image / Qualité image
var _hd_m = text.match(/(?:image\s+(?:hd|4k|haute\s+d[eé]finition|qualit[eé]|premium|pro)|upscal[ez]r?)\s+(?:de|pour|du|:)?\s*(.+)/i);
if (_hd_m) {
var hdPrompt = _hd_m[1].trim();
fetch('/api/ambre-tool-image-upscale.php', {method:'POST', headers:{'Content-Type':'application/json'}, body:JSON.stringify({prompt: hdPrompt})})
.then(function(r){ return r.text().then(function(t){ try{return JSON.parse(t);}catch(e){return null;} }); })
.then(function(data){
hideThinking();
var elapsed = ((performance.now()-startTime)/1000).toFixed(1);
var resp;
if (data && 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});
var msgEl = addMsg('assistant', resp, elapsed);
if (msgEl && msgEl.querySelector('.msg-inner')) {
var b = document.createElement('div'); b.className = 'nx-badges';
b.innerHTML = '<span class="nx-badge" style="background:rgba(236,72,153,0.15);color:#EC4899">🎨 HD 4K</span>';
msgEl.querySelector('.msg-inner').appendChild(b);
}
busy=false; try{var s=document.getElementById("sendBtn");if(s)s.disabled=false;}catch(e){}
try{var m=document.getElementById("msgInput");if(m){m.value="";m.disabled=false;}}catch(e){}
}).catch(function(){busy=false;});
return;
}
// -- YouTube summary
var _yt_m = text.match(/(https?:\/\/(?:www\.)?(?:youtube\.com\/watch\?v=|youtu\.be\/)[\w-]{11}[^\s]*)/);
if (_yt_m) {
var ytUrl = _yt_m[1];
fetch('/api/ambre-tool-youtube-summary.php', {method:'POST', headers:{'Content-Type':'application/json'}, body:JSON.stringify({url: ytUrl})})
.then(function(r){ return r.text().then(function(t){ try{return JSON.parse(t);}catch(e){return null;} }); })
.then(function(data){
hideThinking();
var elapsed = ((performance.now()-startTime)/1000).toFixed(1);
var resp = data && data.summary ? ('🎥 **Résumé vidéo** : ' + ytUrl + '\n\n' + data.summary) : ('❌ Vidéo non résumable (transcription indisponible)');
chatHistory.push({role:'assistant', content:resp});
var msgEl = addMsg('assistant', resp, elapsed);
if (msgEl && msgEl.querySelector('.msg-inner')) {
var b = document.createElement('div'); b.className = 'nx-badges';
b.innerHTML = '<span class="nx-badge" style="background:rgba(239,68,68,0.15);color:#EF4444">🎥 Video</span>';
msgEl.querySelector('.msg-inner').appendChild(b);
}
busy=false; try{var s=document.getElementById("sendBtn");if(s)s.disabled=false;}catch(e){}
try{var m=document.getElementById("msgInput");if(m){m.value="";m.disabled=false;}}catch(e){}
}).catch(function(){busy=false;});
return;
}
// === END AMBRE-V7-PREMIUM-TOOLS ===
// === AMBRE-V6-TOOLS 2026-04-21 · smart tool routing: real image, web search, URL summary, calc ===
var _ambre_text_lc = text.toLowerCase().trim();