115 lines
4.4 KiB
PHP
115 lines
4.4 KiB
PHP
<?php
|
|
// WEVAL — ERP Gap Scans API
|
|
// GET /api/erp-gap-scans.php[?erp=<id>&min_conf=0.5&limit=20&source=llm|rss|playwright]
|
|
// Returns aggregated scan data for pain-points-atlas integration
|
|
|
|
header('Content-Type: application/json');
|
|
header('Cache-Control: public, max-age=60');
|
|
header('Access-Control-Allow-Origin: *');
|
|
|
|
$erp = $_GET['erp'] ?? null;
|
|
$min_conf = isset($_GET['min_conf']) ? (float)$_GET['min_conf'] : 0.3;
|
|
$limit = isset($_GET['limit']) ? min(100, (int)$_GET['limit']) : 50;
|
|
$source = $_GET['source'] ?? null; // llm|rss|playwright
|
|
|
|
try {
|
|
$pdo = new PDO('pgsql:host=10.1.0.3;port=5432;dbname=adx_system', 'admin', 'admin123', [
|
|
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
|
|
PDO::ATTR_TIMEOUT => 3,
|
|
]);
|
|
|
|
// Source filter
|
|
$source_clause = "";
|
|
$params_stats = [];
|
|
if ($source) {
|
|
$source_clause = " WHERE query LIKE :source_pattern";
|
|
$params_stats[':source_pattern'] = $source . '_%';
|
|
}
|
|
|
|
// Global stats
|
|
$stmt = $pdo->prepare("SELECT
|
|
COUNT(*) as total_gaps,
|
|
COUNT(DISTINCT erp_id) as erps_covered,
|
|
ROUND(AVG(confidence_score)::NUMERIC, 3) as avg_confidence,
|
|
MAX(scanned_at) as last_scan_at,
|
|
COUNT(*) FILTER (WHERE query LIKE 'llm_%') as gaps_llm,
|
|
COUNT(*) FILTER (WHERE query LIKE 'rss_%') as gaps_rss,
|
|
COUNT(*) FILTER (WHERE query LIKE 'playwright%') as gaps_playwright
|
|
FROM erp_gap_scans" . $source_clause);
|
|
$stmt->execute($params_stats);
|
|
$stats = $stmt->fetch(PDO::FETCH_ASSOC);
|
|
|
|
// Per-ERP breakdown
|
|
$stmt = $pdo->prepare("-- V96.4: GROUP BY erp_id only (not erp_name) to avoid duplicates (Oracle Fusion vs Oracle Fusion Cloud ERP)
|
|
SELECT
|
|
erp_id,
|
|
MAX(erp_name) as erp_name, -- canonical display name
|
|
COUNT(*) as gaps_count,
|
|
ROUND(AVG(confidence_score)::NUMERIC, 3) as avg_conf,
|
|
MAX(scanned_at) as last_scan,
|
|
array_agg(DISTINCT CASE
|
|
WHEN query LIKE 'llm_%' THEN 'LLM'
|
|
WHEN query LIKE 'rss_%' THEN 'RSS'
|
|
WHEN query LIKE 'playwright%' THEN 'Playwright'
|
|
ELSE 'Other'
|
|
END) as sources
|
|
FROM erp_gap_scans" . $source_clause . "
|
|
GROUP BY erp_id
|
|
ORDER BY gaps_count DESC");
|
|
$stmt->execute($params_stats);
|
|
$per_erp = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
|
|
|
// Detail gaps (filtered)
|
|
$detail_sql = "SELECT id, erp_id, erp_name, title, snippet, source_url, confidence_score, keywords,
|
|
CASE
|
|
WHEN query LIKE 'llm_%' THEN 'LLM'
|
|
WHEN query LIKE 'rss_%' THEN 'RSS'
|
|
WHEN query LIKE 'playwright%' THEN 'Playwright'
|
|
ELSE 'Other'
|
|
END as source,
|
|
scanned_at
|
|
FROM erp_gap_scans
|
|
WHERE confidence_score >= :min_conf";
|
|
$params = [':min_conf' => $min_conf];
|
|
if ($erp) { $detail_sql .= " AND erp_id = :erp"; $params[':erp'] = $erp; }
|
|
if ($source) { $detail_sql .= " AND query LIKE :src"; $params[':src'] = $source . '_%'; }
|
|
$detail_sql .= " ORDER BY confidence_score DESC, scanned_at DESC LIMIT " . (int)$limit;
|
|
$stmt = $pdo->prepare($detail_sql);
|
|
$stmt->execute($params);
|
|
$details = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
|
|
|
// Latest scans per source
|
|
$stmt = $pdo->query("SELECT
|
|
CASE
|
|
WHEN query LIKE 'llm_%' THEN 'LLM'
|
|
WHEN query LIKE 'rss_%' THEN 'RSS'
|
|
WHEN query LIKE 'playwright%' THEN 'Playwright'
|
|
ELSE 'Other'
|
|
END as source,
|
|
MAX(scanned_at) as last_scan,
|
|
COUNT(*) as gaps,
|
|
COUNT(DISTINCT erp_id) as erps
|
|
FROM erp_gap_scans GROUP BY source ORDER BY last_scan DESC");
|
|
$sources = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
|
|
|
echo json_encode([
|
|
'generated_at' => date('c'),
|
|
'version' => 'V96',
|
|
'module' => 'ERP Gap Scans — consolidated D+C+B',
|
|
'stats' => $stats,
|
|
'sources' => $sources,
|
|
'per_erp' => $per_erp,
|
|
'gaps' => $details,
|
|
'filters_applied' => [
|
|
'erp' => $erp,
|
|
'min_confidence' => $min_conf,
|
|
'limit' => $limit,
|
|
'source' => $source,
|
|
],
|
|
], JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);
|
|
|
|
} catch (Exception $e) {
|
|
http_response_code(500);
|
|
echo json_encode(['error' => 'db_error', 'message' => $e->getMessage()]);
|
|
}
|