cii-text-analysis/Lib/Discriminant/AlertAnalyzer.php
Jéremy Munsch f68d2ac333
premier poc
2026-02-11 08:24:04 +01:00

119 lines
3.5 KiB
PHP

<?php
declare(strict_types=1);
namespace Classifier\Lib\Discriminant;
use Classifier\Lib\Utils\StringCleaner;
class AlertAnalyzer
{
/**
* Seuil de confiance pour déclencher une alerte (0.0 à 1.0)
*/
public const CONFIDENCE_THRESHOLD = 0.75;
/**
* Seuil de similarité pour les mots simples (0.0 à 1.0)
*/
private const SIMILARITY_THRESHOLD = 0.85;
/** @var WhiteList */
private $whiteList;
/** @var BlackList */
private $blackList;
/** @var StringCleaner */
private $cleaner;
/** @var int */
private $activationThreshold;
public function __construct(
WhiteList $whiteList,
BlackList $blackList,
StringCleaner $cleaner,
int $activationThreshold = 100
) {
$this->whiteList = $whiteList;
$this->blackList = $blackList;
$this->cleaner = $cleaner;
$this->activationThreshold = $activationThreshold;
}
public function analyze(string $rawText): AnalyzeResult
{
$cleanChain = $this->cleaner->getCleanChain($rawText);
$words = $this->cleaner->preprocessMessage($rawText);
$totalScore = 0.0;
$found = [];
foreach ($this->whiteList->getKeywords() as $keyword => $weight) {
// * Nettoyage rapide du mot-clé lui-même (au cas où il ait des accents)
$cleanKeyword = $this->cleaner->getCleanChain($keyword);
if (strpos($cleanKeyword, ' ') !== false) {
// * RECHERCHE DE MOTS COMPOSÉS (Exacte ou Fuzzy sur chaîne)
if (mb_strpos($cleanChain, $cleanKeyword) !== false) {
$totalScore += $weight;
$found[] = $keyword;
}
} else {
// * RECHERCHE DE MOT SIMPLE (Fuzzy Levenshtein)
$similarity = $this->findBestSimilarity($cleanKeyword, $words);
if ($similarity > self::SIMILARITY_THRESHOLD) {
$totalScore += ($weight * $similarity);
$found[] = $keyword;
}
}
}
foreach ($this->blackList->getKeywords() as $badWord) {
if (mb_strpos($cleanChain, $this->cleaner->getCleanChain($badWord)) !== false) {
return new AnalyzeResult(
0.0,
0.0,
false,
true,
"Blacklist : {$badWord}"
);
}
}
// NOTE: Si le score dépasse le seuil, la confiance est de 100% (1.0)
$confidence = min(1.0, $totalScore / $this->activationThreshold);
return new AnalyzeResult(
round($confidence, 2),
$totalScore,
$confidence >= self::CONFIDENCE_THRESHOLD,
false,
!empty($found) ?
'Keywords found: ' . implode(', ', $found) :
'No keywords found',
$found
);
}
private function findBestSimilarity(string $keyword, array $words): float
{
$best = 0.0;
foreach ($words as $word) {
$dist = levenshtein($keyword, $word);
$maxLen = max(strlen($keyword), strlen($word));
if ($maxLen === 0) {
continue;
}
$sim = 1 - ($dist / $maxLen);
if ($sim > $best) {
$best = $sim;
}
if ($best == 1.0) {
break;
}
}
return $best;
}
}