Files
LogPatternExtractor/Tester/QualityTest.py
2026-05-02 18:33:38 +03:00

97 lines
4.3 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import difflib
import os
import re
from Generator.LogGenerator import LogGenerator
from Processor.StreamingLogCluster import StreamingLogCluster
from Tester.RegressionMetricsCalculator import RegressionMetricsCalculator
def evaluate_template_similarity(gt_template: str, gen_template: str) -> dict:
"""
Оценивает схожесть сгенерированного шаблона (gen) с эталонным (gt - Ground Truth).
"""
# 1. Разбиваем шаблоны на сегменты (текст и теги <...>)
gt_parts = [p for p in re.split(r'(<[^>]+>)', gt_template) if p]
gen_parts = [p for p in re.split(r'(<[^>]+>)', gen_template) if p]
# --- СТРОГАЯ ПРОВЕРКА (Regex) ---
# Создаем регулярное выражение из эталона:
# Текст должен совпасть жестко, а переменные эталона могут проглотить что угодно (.*)
regex_pattern = '^'
for part in gt_parts:
if part.startswith('<') and part.endswith('>'):
regex_pattern += '(.*)'
else:
regex_pattern += re.escape(part)
regex_pattern += '$'
# Подготавливаем Gen: заменяем его переменные на нулевой байт,
# чтобы они поглотились `(.*)`, но не совпали с реальным текстом случайно
gen_string_for_regex = re.sub(r'<[^>]+>', '\x00', gen_template)
is_perfect_structure = bool(re.match(regex_pattern, gen_string_for_regex, flags=re.DOTALL))
# --- МЯГКАЯ ОЦЕНКА В ПРОЦЕНТАХ (Preservation Score) ---
# Достаем только жесткие константы, выбрасывая все переменные
gt_consts = "".join(p for p in gt_parts if not (p.startswith('<') and p.endswith('>')))
gen_consts = "".join(p for p in gen_parts if not (p.startswith('<') and p.endswith('>')))
# Сравниваем, насколько "скелет" Gen содержит внутри себя "скелет" Эталона
matcher = difflib.SequenceMatcher(None, gt_consts, gen_consts)
# Считаем сумму символов эталона, которые остались на своих местах
matched_chars = sum(block.size for block in matcher.get_matching_blocks())
# Считаем процент от 0.0 до 1.0
preservation_score = matched_chars / len(gt_consts) if gt_consts else 1.0
return {
"is_perfect": is_perfect_structure, # True, если структура не нарушена вообще
"score": round(preservation_score, 4), # 1.0 = Идеал, < 1.0 = Переменные "съели" константы
}
if __name__ == '__main__':
gen = LogGenerator()
metrics = RegressionMetricsCalculator()
MODEL_PATH = '../Resources/model'
DB_FILE = "../Resources/logs.db"
if os.path.exists(DB_FILE):
os.remove(DB_FILE)
print("--- ЗАПУСК: Delta Mode ---")
clusterer = StreamingLogCluster(MODEL_PATH, db_path=DB_FILE)
# Генерируем 10 примеров
for i in range(1):
# 1. Получаем объект Term
term = gen.generate()
# 3. Используем данные (например, сохраняем в JSON для обучения)
print(f"--- Sample {i + 1} ---")
template = term.structure().text
print(f"Template :{template}")
for j in range(10):
# 2. Рендерим его в строку и метаданные
log = term.render(0.5)
processed = clusterer.process(log.text)
eval_result = evaluate_template_similarity(template, processed['template_view'])
score = eval_result['score']
metrics.add_sample(score)
print(f"Positive {j}: {processed['template_view']}")
#print(score)
print(f"Template : {template}")
# # --- ВЫВОДИТ ИТОГОВЫЕ МЕТРИКИ В КОНЦЕ СКРИПТА ---
# print("\n" + "=" * 40)
# print("Метрики:")
# print("=" * 40)
# results = metrics.calculate()
# for metric_name, value in results.items():
# print(f"{metric_name:<10}: {value}")