56 lines
1.8 KiB
PHP
56 lines
1.8 KiB
PHP
<?php
|
|
/**
|
|
* WEVAL CSAT - Customer Satisfaction Score sovereign 21avr2026
|
|
* Rating 1-5 after resolved ticket/interaction.
|
|
* Storage: /opt/weval-l99/data/csat-responses.jsonl
|
|
*/
|
|
header('Content-Type: application/json');
|
|
|
|
$STORAGE = '/opt/weval-l99/data/csat-responses.jsonl';
|
|
@mkdir(dirname($STORAGE), 0755, true);
|
|
|
|
$action = $_GET['action'] ?? ($_POST['action'] ?? 'stats');
|
|
|
|
if ($action === 'submit' && $_SERVER['REQUEST_METHOD'] === 'POST') {
|
|
$rating = intval($_POST['rating'] ?? -1);
|
|
$context = substr(trim($_POST['context'] ?? ''), 0, 200);
|
|
$user = substr(trim($_POST['user'] ?? 'anonymous'), 0, 60);
|
|
if ($rating < 1 || $rating > 5) {
|
|
echo json_encode(['ok'=>false,'error'=>'invalid_rating','expected'=>'1-5']);
|
|
exit;
|
|
}
|
|
@file_put_contents($STORAGE, json_encode(['ts'=>date('c'),'rating'=>$rating,'context'=>$context,'user'=>$user])."\n", FILE_APPEND | LOCK_EX);
|
|
echo json_encode(['ok'=>true,'recorded'=>true]);
|
|
exit;
|
|
}
|
|
|
|
$responses = [];
|
|
if (is_readable($STORAGE)) {
|
|
foreach (file($STORAGE) as $line) {
|
|
$r = @json_decode(trim($line), true);
|
|
if ($r && isset($r['rating'])) $responses[] = $r;
|
|
}
|
|
}
|
|
|
|
$n = count($responses);
|
|
if ($n === 0) {
|
|
echo json_encode(['ok'=>true,'source'=>'sovereign_jsonl','ts'=>date('c'),'csat_score_pct'=>0,'responses_total'=>0,'status'=>'wire_needed','drill'=>'No ratings yet. POST /api/csat-api.php?action=submit']);
|
|
exit;
|
|
}
|
|
|
|
// CSAT = % ratings >= 4 (out of 5)
|
|
$satisfied = 0;
|
|
foreach ($responses as $r) if ($r['rating'] >= 4) $satisfied++;
|
|
$pct = round(($satisfied / $n) * 100);
|
|
|
|
echo json_encode([
|
|
'ok'=>true,
|
|
'source'=>'sovereign_jsonl',
|
|
'ts'=>date('c'),
|
|
'csat_score_pct'=>$pct,
|
|
'responses_total'=>$n,
|
|
'satisfied_count'=>$satisfied,
|
|
'status'=>$pct >= 85 ? 'ok' : ($pct > 0 ? 'warn' : 'wire_needed'),
|
|
'drill'=>"% ratings >=4 out of 5",
|
|
]);
|