2025-10-16 10:52:09 +03:00
|
|
|
|
#!/usr/bin/env python3
|
|
|
|
|
|
"""
|
|
|
|
|
|
Объединение результатов AI Agent и Regex в единую структуру
|
|
|
|
|
|
"""
|
|
|
|
|
|
import json
|
|
|
|
|
|
|
|
|
|
|
|
# Определяем 17 критериев
|
|
|
|
|
|
CRITERIA = [
|
|
|
|
|
|
{
|
|
|
|
|
|
"id": 1,
|
|
|
|
|
|
"name": "Юридическая идентификация и верификация",
|
|
|
|
|
|
"description": "ИНН, ОГРН, полное наименование организации"
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
"id": 2,
|
|
|
|
|
|
"name": "Адрес",
|
|
|
|
|
|
"description": "Юридический и фактический адрес, местонахождение"
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
"id": 3,
|
|
|
|
|
|
"name": "Контакты",
|
|
|
|
|
|
"description": "Телефон, email, форма обратной связи"
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
"id": 4,
|
|
|
|
|
|
"name": "Режим работы",
|
|
|
|
|
|
"description": "Часы работы, график приема, колл-центр"
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
"id": 5,
|
|
|
|
|
|
"name": "Политика ПДн (152-ФЗ)",
|
|
|
|
|
|
"description": "Политика персональных данных, обработка ПДн"
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
"id": 7,
|
|
|
|
|
|
"name": "Договор-оферта / Правила оказания услуг",
|
|
|
|
|
|
"description": "Публичная оферта, пользовательское соглашение, условия"
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
"id": 8,
|
|
|
|
|
|
"name": "Рекламации и споры",
|
|
|
|
|
|
"description": "Претензии, возврат, обмен, жалобы"
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
"id": 9,
|
|
|
|
|
|
"name": "Цены/прайс",
|
|
|
|
|
|
"description": "Цены, стоимость, тарифы"
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
"id": 10,
|
|
|
|
|
|
"name": "Способы оплаты",
|
|
|
|
|
|
"description": "Наличные, карта, СБП"
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
"id": 11,
|
|
|
|
|
|
"name": "Онлайн-оплата",
|
|
|
|
|
|
"description": "Эквайринг, оплата онлайн"
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
"id": 12,
|
|
|
|
|
|
"name": "Онлайн-бронирование",
|
|
|
|
|
|
"description": "Забронировать, booking"
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
"id": 13,
|
|
|
|
|
|
"name": "FAQ",
|
|
|
|
|
|
"description": "Частые вопросы, вопрос-ответ"
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
"id": 14,
|
|
|
|
|
|
"name": "Доступность для ЛОВЗ",
|
|
|
|
|
|
"description": "Инвалиды, безбарьерная среда, маломобильные"
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
"id": 15,
|
|
|
|
|
|
"name": "Партнёры/бренды",
|
|
|
|
|
|
"description": "Партнеры, поставщики, сотрудничество"
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
"id": 16,
|
|
|
|
|
|
"name": "Команда/сотрудники",
|
|
|
|
|
|
"description": "Команда, персонал, руководство"
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
"id": 17,
|
|
|
|
|
|
"name": "Уголок потребителя",
|
|
|
|
|
|
"description": "Права потребителей, защита"
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
"id": 18,
|
|
|
|
|
|
"name": "Актуальность документов",
|
|
|
|
|
|
"description": "Дата обновления, версия"
|
|
|
|
|
|
}
|
|
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def merge_results(ai_results, regex_results):
|
|
|
|
|
|
"""
|
|
|
|
|
|
Объединяет результаты AI Agent и Regex
|
|
|
|
|
|
|
|
|
|
|
|
ai_results: список из 17 элементов с детальными ответами AI
|
|
|
|
|
|
regex_results: список из 17 элементов с простыми ДА/НЕТ от regex
|
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
|
|
merged = []
|
|
|
|
|
|
|
|
|
|
|
|
for i, criterion in enumerate(CRITERIA):
|
|
|
|
|
|
# Берём результаты AI и Regex для этого критерия
|
|
|
|
|
|
ai_result = ai_results[i] if i < len(ai_results) else {}
|
|
|
|
|
|
regex_result = regex_results[i] if i < len(regex_results) else {}
|
|
|
|
|
|
|
|
|
|
|
|
# Извлекаем данные из AI результата
|
|
|
|
|
|
ai_output = ai_result.get('output', {})
|
|
|
|
|
|
ai_found = ai_output.get('found', False)
|
|
|
|
|
|
ai_score = ai_output.get('score', 0)
|
|
|
|
|
|
ai_quote = ai_output.get('quote', '')
|
|
|
|
|
|
ai_url = ai_output.get('url', '')
|
|
|
|
|
|
ai_details = ai_output.get('details', '')
|
|
|
|
|
|
ai_confidence = ai_output.get('confidence', 'Не определена')
|
|
|
|
|
|
ai_checked_pages = ai_output.get('checked_pages', 0)
|
|
|
|
|
|
|
|
|
|
|
|
# Извлекаем данные из Regex результата
|
|
|
|
|
|
regex_output = regex_result.get('output', {})
|
|
|
|
|
|
regex_found = regex_output.get('found', False)
|
|
|
|
|
|
regex_answer = regex_output.get('answer', 'НЕТ')
|
|
|
|
|
|
regex_extracted = regex_output.get('extracted', '')
|
|
|
|
|
|
regex_confidence = regex_output.get('confidence', 'Не определена')
|
|
|
|
|
|
|
|
|
|
|
|
# Объединяем результаты
|
|
|
|
|
|
merged_item = {
|
|
|
|
|
|
"criterion_id": criterion['id'],
|
|
|
|
|
|
"criterion_name": criterion['name'],
|
|
|
|
|
|
"criterion_description": criterion['description'],
|
|
|
|
|
|
|
|
|
|
|
|
# Общий результат (ДА если хотя бы один метод нашёл)
|
|
|
|
|
|
"found": ai_found or regex_found,
|
|
|
|
|
|
"status": "НАЙДЕНО" if (ai_found or regex_found) else "НЕ НАЙДЕНО",
|
|
|
|
|
|
|
|
|
|
|
|
# Оценка (0-1)
|
|
|
|
|
|
"score": max(ai_score, 1 if regex_found else 0),
|
|
|
|
|
|
|
|
|
|
|
|
# AI Agent результаты
|
|
|
|
|
|
"ai_agent": {
|
|
|
|
|
|
"found": ai_found,
|
|
|
|
|
|
"score": ai_score,
|
|
|
|
|
|
"quote": ai_quote,
|
|
|
|
|
|
"url": ai_url,
|
|
|
|
|
|
"details": ai_details,
|
|
|
|
|
|
"confidence": ai_confidence,
|
|
|
|
|
|
"checked_pages": ai_checked_pages
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
# Regex результаты
|
|
|
|
|
|
"regex": {
|
|
|
|
|
|
"found": regex_found,
|
|
|
|
|
|
"answer": regex_answer,
|
|
|
|
|
|
"extracted": regex_extracted,
|
|
|
|
|
|
"confidence": regex_confidence
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
# Итоговая уверенность
|
|
|
|
|
|
"final_confidence": _calculate_final_confidence(ai_confidence, regex_confidence, ai_found, regex_found)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
merged.append(merged_item)
|
|
|
|
|
|
|
|
|
|
|
|
return merged
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def _calculate_final_confidence(ai_conf, regex_conf, ai_found, regex_found):
|
|
|
|
|
|
"""Рассчитывает итоговую уверенность"""
|
|
|
|
|
|
|
|
|
|
|
|
# Если оба нашли - высокая
|
|
|
|
|
|
if ai_found and regex_found:
|
|
|
|
|
|
return "Очень высокая"
|
|
|
|
|
|
|
|
|
|
|
|
# Если один нашёл с высокой уверенностью
|
|
|
|
|
|
if (ai_found and ai_conf == "Высокая") or (regex_found and regex_conf == "Высокая"):
|
|
|
|
|
|
return "Высокая"
|
|
|
|
|
|
|
|
|
|
|
|
# Если один нашёл со средней уверенностью
|
|
|
|
|
|
if (ai_found and ai_conf == "Средняя") or (regex_found and regex_conf == "Средняя"):
|
|
|
|
|
|
return "Средняя"
|
|
|
|
|
|
|
|
|
|
|
|
# Если оба не нашли с высокой уверенностью - точно нет
|
|
|
|
|
|
if not ai_found and not regex_found and ai_conf == "Высокая" and regex_conf == "Высокая":
|
|
|
|
|
|
return "Высокая (не найдено)"
|
|
|
|
|
|
|
|
|
|
|
|
# Иначе - низкая
|
|
|
|
|
|
return "Низкая"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def format_summary(merged_results):
|
|
|
|
|
|
"""Форматирует краткую сводку"""
|
|
|
|
|
|
|
|
|
|
|
|
total = len(merged_results)
|
|
|
|
|
|
found_count = sum(1 for r in merged_results if r['found'])
|
|
|
|
|
|
not_found_count = total - found_count
|
|
|
|
|
|
|
|
|
|
|
|
summary = {
|
|
|
|
|
|
"hotel_name": "Городской отель \"Комфорт\"",
|
|
|
|
|
|
"region": "Камчатский край",
|
|
|
|
|
|
"audit_date": "2025-10-14",
|
|
|
|
|
|
"total_criteria": total,
|
|
|
|
|
|
"found": found_count,
|
|
|
|
|
|
"not_found": not_found_count,
|
|
|
|
|
|
"compliance_percentage": round(found_count / total * 100, 1),
|
|
|
|
|
|
"criteria_results": merged_results
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return summary
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def print_summary(summary):
|
|
|
|
|
|
"""Выводит красивую сводку"""
|
|
|
|
|
|
|
|
|
|
|
|
print(f"\n{'='*80}")
|
|
|
|
|
|
print(f"📊 СВОДКА АУДИТА: {summary['hotel_name']}")
|
|
|
|
|
|
print(f"{'='*80}")
|
|
|
|
|
|
print(f"\n📍 Регион: {summary['region']}")
|
|
|
|
|
|
print(f"📅 Дата аудита: {summary['audit_date']}")
|
|
|
|
|
|
print(f"\n✅ Найдено: {summary['found']}/{summary['total_criteria']} ({summary['compliance_percentage']}%)")
|
|
|
|
|
|
print(f"❌ Не найдено: {summary['not_found']}/{summary['total_criteria']}")
|
|
|
|
|
|
|
|
|
|
|
|
print(f"\n{'='*80}")
|
|
|
|
|
|
print("ДЕТАЛЬНЫЕ РЕЗУЛЬТАТЫ:")
|
|
|
|
|
|
print(f"{'='*80}\n")
|
|
|
|
|
|
|
|
|
|
|
|
for result in summary['criteria_results']:
|
|
|
|
|
|
status_icon = "✅" if result['found'] else "❌"
|
|
|
|
|
|
print(f"{status_icon} [{result['criterion_id']}] {result['criterion_name']}")
|
|
|
|
|
|
print(f" Статус: {result['status']}")
|
|
|
|
|
|
print(f" Оценка: {result['score']}")
|
|
|
|
|
|
print(f" Уверенность: {result['final_confidence']}")
|
|
|
|
|
|
|
|
|
|
|
|
if result['ai_agent']['found']:
|
|
|
|
|
|
print(f" 🤖 AI Agent: найдено")
|
|
|
|
|
|
if result['ai_agent']['url']:
|
|
|
|
|
|
print(f" URL: {result['ai_agent']['url']}")
|
|
|
|
|
|
if result['ai_agent']['details']:
|
|
|
|
|
|
print(f" Детали: {result['ai_agent']['details'][:100]}...")
|
|
|
|
|
|
|
|
|
|
|
|
if result['regex']['found']:
|
|
|
|
|
|
print(f" 🔍 Regex: найдено")
|
|
|
|
|
|
if result['regex']['extracted']:
|
|
|
|
|
|
print(f" Извлечено: {result['regex']['extracted'][:100]}...")
|
|
|
|
|
|
|
|
|
|
|
|
print()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Пример использования
|
|
|
|
|
|
if __name__ == "__main__":
|
|
|
|
|
|
# Загружаем данные из файла или используем переданные
|
|
|
|
|
|
import sys
|
|
|
|
|
|
|
|
|
|
|
|
if len(sys.argv) > 1:
|
|
|
|
|
|
# Загружаем из файла
|
|
|
|
|
|
with open(sys.argv[1], 'r', encoding='utf-8') as f:
|
|
|
|
|
|
data = json.load(f)
|
|
|
|
|
|
else:
|
|
|
|
|
|
# Используем тестовые данные
|
|
|
|
|
|
print("⚠️ Использование: python merge_audit_results.py <файл_с_результатами.json>")
|
|
|
|
|
|
print(" Или передайте данные через stdin")
|
|
|
|
|
|
sys.exit(1)
|
|
|
|
|
|
|
|
|
|
|
|
# Разделяем на AI и Regex результаты
|
|
|
|
|
|
# Первые 17 - от AI Agent, последние 17 - от Regex
|
|
|
|
|
|
ai_results = data[:17]
|
|
|
|
|
|
regex_results = data[17:34]
|
|
|
|
|
|
|
|
|
|
|
|
# Объединяем
|
|
|
|
|
|
merged = merge_results(ai_results, regex_results)
|
|
|
|
|
|
|
|
|
|
|
|
# Формируем сводку
|
|
|
|
|
|
summary = format_summary(merged)
|
|
|
|
|
|
|
|
|
|
|
|
# Выводим
|
|
|
|
|
|
print_summary(summary)
|
|
|
|
|
|
|
|
|
|
|
|
# Сохраняем в файл
|
|
|
|
|
|
output_file = "audit_merged_results.json"
|
|
|
|
|
|
with open(output_file, 'w', encoding='utf-8') as f:
|
|
|
|
|
|
json.dump(summary, f, ensure_ascii=False, indent=2)
|
|
|
|
|
|
|
|
|
|
|
|
print(f"\n💾 Результаты сохранены в {output_file}")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2025-10-27 22:49:42 +03:00
|
|
|
|
|