✨ Major Features: - Complete RAG system for hotel website analysis - Hybrid audit with BGE-M3 embeddings + Natasha NER - Universal horizontal Excel reports with dashboards - Multi-region processing (SPb, Orel, Chukotka, Kamchatka) 📊 Completed Regions: - Орловская область: 100% (36/36) - Чукотский АО: 100% (4/4) - г. Санкт-Петербург: 93% (893/960) - Камчатский край: 87% (89/102) 🔧 Infrastructure: - PostgreSQL with pgvector extension - BGE-M3 embeddings API - Browserless for web scraping - N8N workflows for automation - S3/Nextcloud file storage 📝 Documentation: - Complete DB schemas - API documentation - Setup guides - Status reports
161 lines
4.8 KiB
JavaScript
161 lines
4.8 KiB
JavaScript
// 🎯 CODE NODE: Проверка регулярными выражениями
|
||
// Размести эту ноду ПОСЛЕ AI Agent
|
||
// Она улучшит оценку, если найдёт точные форматы (ИНН, телефоны, email)
|
||
|
||
// Получаем данные от AI Agent
|
||
const aiResult = $input.item.json;
|
||
|
||
// Получаем текст из chunks (должен быть в контексте)
|
||
// Если у тебя есть отдельная нода для получения chunks - используй её
|
||
// Иначе - нужно сделать дополнительный запрос к PostgreSQL
|
||
const hotelText = $('Postgres1').all().map(item => item.json.text).join(' ');
|
||
|
||
// Регулярные выражения для каждого критерия
|
||
const regexPatterns = {
|
||
1: { // ИНН, ОГРН
|
||
patterns: [
|
||
/\b\d{10}\b/g, // ИНН юр.лица (10 цифр)
|
||
/\b\d{12}\b/g, // ИНН ИП (12 цифр)
|
||
/\b\d{13}\b/g, // ОГРН (13 цифр)
|
||
/\b\d{15}\b/g, // ОГРНИП (15 цифр)
|
||
/инн\s*:?\s*\d{10,12}/gi,
|
||
/огрн\s*:?\s*\d{13}/gi
|
||
],
|
||
weight: 1.0
|
||
},
|
||
2: { // Адрес
|
||
patterns: [
|
||
/\d{6}.*?ул\./gi,
|
||
/ул\.\s*[А-Яа-яёЁA-Za-z\s]+,?\s*\d+/gi,
|
||
/\d{6},?\s*г\.\s*[А-Яа-яёЁ-]+/gi
|
||
],
|
||
weight: 1.0
|
||
},
|
||
3: { // Контакты
|
||
patterns: [
|
||
/(?:\+7|8)\s*\(?\d{3,5}\)?\s*\d{1,3}[-\s]?\d{2}[-\s]?\d{2}/g, // Телефон
|
||
/[\w\.-]+@[\w\.-]+\.\w{2,}/g // Email
|
||
],
|
||
weight: 1.0
|
||
},
|
||
4: { // Режим работы
|
||
patterns: [
|
||
/(?:с|с\s+)\d{1,2}(?::|\.)\d{2}\s*(?:до|по)\s*\d{1,2}(?::|\.)\d{2}/gi,
|
||
/круглосуточно/gi,
|
||
/24\s*[/\-]\s*7/g
|
||
],
|
||
weight: 1.0
|
||
},
|
||
5: { // 152-ФЗ
|
||
patterns: [
|
||
/152[-\s]?фз/gi,
|
||
/политика\s+в\s+отношении\s+обработки\s+персональных\s+данных/gi
|
||
],
|
||
weight: 1.0
|
||
},
|
||
7: { // Договор-оферта
|
||
patterns: [
|
||
/публичная\s+оферта/gi,
|
||
/договор.*?оказани.*?услуг/gi,
|
||
/пользовательское\s+соглашение/gi
|
||
],
|
||
weight: 1.0
|
||
},
|
||
9: { // Цены
|
||
patterns: [
|
||
/\d+\s*(?:руб|₽)/g,
|
||
/(?:от|цена|стоимость)\s*\d+/gi
|
||
],
|
||
weight: 0.8
|
||
},
|
||
12: { // Онлайн-бронирование
|
||
patterns: [
|
||
/забронировать/gi,
|
||
/форма\s+(?:заявки|бронирования)/gi
|
||
],
|
||
weight: 0.8
|
||
}
|
||
};
|
||
|
||
// Функция проверки паттернов
|
||
function checkPatterns(text, patterns) {
|
||
const matches = [];
|
||
for (const pattern of patterns) {
|
||
const found = text.match(pattern);
|
||
if (found) {
|
||
matches.push(...found.slice(0, 3)); // Макс 3 совпадения на паттерн
|
||
}
|
||
}
|
||
return matches;
|
||
}
|
||
|
||
// Проверяем текущий критерий
|
||
const criterionId = aiResult.criterion_id || aiResult.id;
|
||
const regexConfig = regexPatterns[criterionId];
|
||
|
||
let regexScore = 0.0;
|
||
let regexMatches = [];
|
||
|
||
if (regexConfig && hotelText) {
|
||
regexMatches = checkPatterns(hotelText, regexConfig.patterns);
|
||
|
||
if (regexMatches.length > 0) {
|
||
regexScore = regexConfig.weight;
|
||
}
|
||
}
|
||
|
||
// ГИБРИДНАЯ ОЦЕНКА: берём максимум из AI и регулярок
|
||
const aiScore = parseFloat(aiResult.score) || 0.0;
|
||
const finalScore = Math.max(aiScore, regexScore);
|
||
|
||
// Определяем метод, который дал результат
|
||
let method = 'Не найдено';
|
||
if (finalScore > 0) {
|
||
if (aiScore > regexScore) {
|
||
method = 'AI Agent';
|
||
} else if (regexScore > aiScore) {
|
||
method = 'Регулярные выражения';
|
||
} else {
|
||
method = 'AI Agent + Регулярки';
|
||
}
|
||
}
|
||
|
||
// Возвращаем улучшенный результат
|
||
return {
|
||
json: {
|
||
criterion_id: criterionId,
|
||
criterion_name: aiResult.criterion_name || aiResult.name,
|
||
question: aiResult.question,
|
||
|
||
// Результаты AI Agent
|
||
ai_score: aiScore,
|
||
ai_found: aiResult.found,
|
||
ai_quote: aiResult.quote || '',
|
||
ai_url: aiResult.url || '',
|
||
|
||
// Результаты регулярок
|
||
regex_score: regexScore,
|
||
regex_matches: regexMatches.slice(0, 5), // Макс 5 совпадений
|
||
regex_found: regexMatches.length > 0,
|
||
|
||
// Итоговая оценка
|
||
final_score: finalScore,
|
||
method: method,
|
||
confidence: finalScore >= 0.8 ? 'Высокая' :
|
||
finalScore >= 0.5 ? 'Средняя' :
|
||
finalScore >= 0.3 ? 'Низкая' : 'Не найдено',
|
||
|
||
// Для отчёта
|
||
quote: aiResult.quote || (regexMatches.length > 0 ? `Найдено: ${regexMatches[0]}` : ''),
|
||
url: aiResult.url || '',
|
||
details: aiResult.details || ''
|
||
}
|
||
};
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|