Проект аудита отелей: основные скрипты и документация
- Краулеры: smart_crawler.py, regional_crawler.py - Аудит: audit_orel_to_excel.py, audit_chukotka_to_excel.py - РКН проверка: check_rkn_registry.py, recheck_unclear_rkn.py - Отчёты: create_orel_horizontal_report.py - Обработка: process_all_hotels_embeddings.py - Документация: README.md, DB_SCHEMA_REFERENCE.md
This commit is contained in:
265
N8N_MERGE_INSTRUCTIONS.md
Normal file
265
N8N_MERGE_INSTRUCTIONS.md
Normal file
@@ -0,0 +1,265 @@
|
||||
# 🔗 Инструкция: Объединение результатов аудита в n8n
|
||||
|
||||
## 📋 Что делает Code Node
|
||||
|
||||
Объединяет результаты от **AI Agent** (17 детальных ответов) и **Regex** (17 простых ДА/НЕТ) в единую структуру с итоговой оценкой.
|
||||
|
||||
---
|
||||
|
||||
## 🏗️ Структура workflow в n8n
|
||||
|
||||
```
|
||||
[Start]
|
||||
↓
|
||||
[Loop Over Items] ← 17 вопросов
|
||||
↓
|
||||
├─→ [AI Agent] → результаты AI (17 items)
|
||||
↓
|
||||
└─→ [Postgres Regex] → результаты Regex (17 items)
|
||||
↓
|
||||
[Aggregate] → объединяем 34 items в один массив
|
||||
↓
|
||||
[Code Node: Merge Results] ← ВОТ СЮДА ВСТАВИТЬ КОД
|
||||
↓
|
||||
[Output] → единая сводка
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📥 Входные данные
|
||||
|
||||
Code Node должен получить **массив из 34 элементов**:
|
||||
|
||||
- **Элементы 0-16** (первые 17): результаты от AI Agent
|
||||
- **Элементы 17-33** (последние 17): результаты от Regex
|
||||
|
||||
### Формат AI Agent (первые 17):
|
||||
```json
|
||||
{
|
||||
"question": "полное наименование организации ОПФ ИНН ОГРН...",
|
||||
"output": {
|
||||
"found": true,
|
||||
"score": 0.5,
|
||||
"quote": "ИП Фролов С.А.",
|
||||
"url": "https://example.com/page",
|
||||
"details": "На сайте найдено...",
|
||||
"checked_pages": 10,
|
||||
"confidence": "Средняя"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Формат Regex (последние 17):
|
||||
```json
|
||||
{
|
||||
"output": {
|
||||
"found": true,
|
||||
"answer": "ДА",
|
||||
"extracted": "ИНН: 1234567890",
|
||||
"confidence": "Высокая"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📤 Выходные данные
|
||||
|
||||
Code Node возвращает **1 элемент** с объединённой сводкой:
|
||||
|
||||
```json
|
||||
{
|
||||
"hotel_name": "Городской отель \"Комфорт\"",
|
||||
"region": "Камчатский край",
|
||||
"audit_date": "2025-10-14",
|
||||
"total_criteria": 17,
|
||||
"found": 5,
|
||||
"not_found": 12,
|
||||
"compliance_percentage": 29.4,
|
||||
"criteria_results": [
|
||||
{
|
||||
"criterion_id": 1,
|
||||
"criterion_name": "Юридическая идентификация и верификация",
|
||||
"criterion_description": "ИНН, ОГРН, полное наименование организации",
|
||||
"found": true,
|
||||
"status": "НАЙДЕНО",
|
||||
"score": 0.5,
|
||||
"final_confidence": "Средняя",
|
||||
"ai_agent": {
|
||||
"found": true,
|
||||
"score": 0.5,
|
||||
"quote": "ИП Фролов С.А.",
|
||||
"url": "https://hotelcomfort41.ru/o-kompanii",
|
||||
"details": "На сайте найдено наименование...",
|
||||
"confidence": "Средняя",
|
||||
"checked_pages": 10
|
||||
},
|
||||
"regex": {
|
||||
"found": false,
|
||||
"answer": "НЕТ",
|
||||
"extracted": "",
|
||||
"confidence": "Высокая"
|
||||
}
|
||||
},
|
||||
// ... остальные 16 критериев
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔧 Как использовать в n8n
|
||||
|
||||
### Шаг 1: Aggregate Node (перед Code Node)
|
||||
|
||||
**Настройки Aggregate:**
|
||||
- **Aggregate**: `Aggregate All Items` (объединить все в один массив)
|
||||
- **Output Field**: оставить пустым или `data`
|
||||
|
||||
Это объединит 34 отдельных items (17 от AI + 17 от Regex) в один массив.
|
||||
|
||||
### Шаг 2: Code Node (вставить код)
|
||||
|
||||
1. Добавь **Code Node** после Aggregate
|
||||
2. Скопируй код из файла `n8n_code_merge_audit_results.js`
|
||||
3. Вставь в Code Node
|
||||
|
||||
**Важно!** Code Node автоматически:
|
||||
- Разделит массив на AI (0-16) и Regex (17-33)
|
||||
- Сопоставит результаты по индексу
|
||||
- Объединит в единую структуру
|
||||
- Вернёт итоговую сводку
|
||||
|
||||
### Шаг 3: Передача данных об отеле
|
||||
|
||||
Code Node пытается получить `hotel_name` и `region` из:
|
||||
1. Workflow variables: `$('Workflow').item.json.hotel_name`
|
||||
2. Первого input item: `$input.first().json.hotel_name`
|
||||
|
||||
**Рекомендация:** Установи workflow variables в начале:
|
||||
```javascript
|
||||
// В первом Code Node workflow
|
||||
return [{
|
||||
json: {
|
||||
hotel_name: "{{ $json.hotel_name }}",
|
||||
region: "{{ $json.region }}",
|
||||
hotel_id: "{{ $json.hotel_id }}"
|
||||
}
|
||||
}];
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📊 Логика объединения
|
||||
|
||||
### Статус `found`:
|
||||
- `true` если **хотя бы один** метод (AI или Regex) нашёл информацию
|
||||
- `false` если оба не нашли
|
||||
|
||||
### Оценка `score` (0-1):
|
||||
- Берётся **максимум** из AI score и Regex (1 если found, 0 если нет)
|
||||
|
||||
### Итоговая уверенность `final_confidence`:
|
||||
|
||||
| AI found | AI conf | Regex found | Regex conf | Итог |
|
||||
|----------|---------|-------------|------------|------|
|
||||
| ✅ | Высокая | ✅ | Высокая | **Очень высокая** |
|
||||
| ✅ | Высокая | ❌ | - | **Высокая** |
|
||||
| ❌ | - | ✅ | Высокая | **Высокая** |
|
||||
| ✅ | Средняя | ❌ | - | **Средняя** |
|
||||
| ❌ | Высокая | ❌ | Высокая | **Высокая (не найдено)** |
|
||||
| ❌ | - | ❌ | - | **Низкая** |
|
||||
|
||||
---
|
||||
|
||||
## 🧪 Пример workflow
|
||||
|
||||
```
|
||||
┌─────────────────────┐
|
||||
│ 1. Start │
|
||||
│ hotel_id: xxx │
|
||||
│ hotel_name: "..." │
|
||||
│ region: "..." │
|
||||
└──────────┬──────────┘
|
||||
│
|
||||
┌──────────▼──────────┐
|
||||
│ 2. Set Variables │ ← Сохраняем hotel_name, region
|
||||
└──────────┬──────────┘
|
||||
│
|
||||
┌──────────▼──────────┐
|
||||
│ 3. Generate Items │ ← Создаём 17 items (вопросы)
|
||||
└──────────┬──────────┘
|
||||
│
|
||||
├─────────────────────────────┐
|
||||
│ │
|
||||
┌──────────▼──────────┐ ┌────────────▼──────────┐
|
||||
│ 4a. AI Agent │ │ 4b. Postgres Regex │
|
||||
│ (17 детальных) │ │ (17 простых ДА/НЕТ) │
|
||||
└──────────┬──────────┘ └────────────┬──────────┘
|
||||
│ │
|
||||
└─────────┬───────────────────┘
|
||||
│
|
||||
┌─────────▼──────────┐
|
||||
│ 5. Aggregate │ ← 34 items → 1 массив
|
||||
└─────────┬──────────┘
|
||||
│
|
||||
┌─────────▼──────────┐
|
||||
│ 6. Code Node │ ← ВСТАВИТЬ КОД СЮДА
|
||||
│ (Merge Results) │
|
||||
└─────────┬──────────┘
|
||||
│
|
||||
┌─────────▼──────────┐
|
||||
│ 7. Save to DB │ ← Сохраняем в hotel_audit_results
|
||||
└────────────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 💾 Сохранение результатов в БД
|
||||
|
||||
После Code Node добавь **Postgres Node** для сохранения:
|
||||
|
||||
```sql
|
||||
INSERT INTO hotel_audit_results
|
||||
(hotel_id, audit_date, total_criteria, found, not_found,
|
||||
compliance_percentage, criteria_results, created_at)
|
||||
VALUES
|
||||
($1, $2, $3, $4, $5, $6, $7::jsonb, NOW())
|
||||
ON CONFLICT (hotel_id, audit_date) DO UPDATE SET
|
||||
total_criteria = EXCLUDED.total_criteria,
|
||||
found = EXCLUDED.found,
|
||||
not_found = EXCLUDED.not_found,
|
||||
compliance_percentage = EXCLUDED.compliance_percentage,
|
||||
criteria_results = EXCLUDED.criteria_results,
|
||||
updated_at = NOW()
|
||||
```
|
||||
|
||||
**Parameters:**
|
||||
1. `{{ $json.hotel_id }}`
|
||||
2. `{{ $json.audit_date }}`
|
||||
3. `{{ $json.total_criteria }}`
|
||||
4. `{{ $json.found }}`
|
||||
5. `{{ $json.not_found }}`
|
||||
6. `{{ $json.compliance_percentage }}`
|
||||
7. `{{ JSON.stringify($json.criteria_results) }}`
|
||||
|
||||
---
|
||||
|
||||
## ✅ Чек-лист
|
||||
|
||||
- [ ] Aggregate Node объединяет 34 items
|
||||
- [ ] Code Node получает массив из 34 элементов
|
||||
- [ ] Первые 17 - от AI Agent (детальные)
|
||||
- [ ] Последние 17 - от Regex (простые)
|
||||
- [ ] Workflow variables содержат hotel_name и region
|
||||
- [ ] Результат сохраняется в БД
|
||||
|
||||
---
|
||||
|
||||
**Файл кода:** `n8n_code_merge_audit_results.js`
|
||||
**Дата:** 2025-10-14
|
||||
**Автор:** Фёдор + AI Assistant
|
||||
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user