🚀 Full project sync: Hotels RAG & Audit System

 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
This commit is contained in:
Фёдор
2025-10-27 22:49:42 +03:00
parent 0cf3297290
commit 684fada337
94 changed files with 14891 additions and 911 deletions

111
n8n_code_natasha_ner.js Normal file
View File

@@ -0,0 +1,111 @@
// 🎯 CODE NODE: Вызов Natasha NER API для извлечения сущностей
// Размести эту ноду ПОСЛЕ получения результатов от регулярок
// Она добавит NER проверку для критериев 1 и 2
const NATASHA_API_URL = 'http://localhost:8004/extract_simple';
// Критерии, которые требуют NER проверки
const NER_CRITERIA = [1, 2]; // 1 - ИНН/ОГРН (организации), 2 - Адрес (локации)
const items = $input.all();
// Обрабатываем каждый критерий
const results = await Promise.all(items.map(async (item) => {
const data = item.json;
const criterionId = parseInt(data.criterion_id);
// Если критерий не требует NER - возвращаем как есть
if (!NER_CRITERIA.includes(criterionId)) {
return {
json: {
...data,
ner_checked: false,
ner_score: 0.0,
ner_entities: []
}
};
}
// Если нет текста для проверки - пропускаем
if (!data.quote || data.quote.length < 10) {
return {
json: {
...data,
ner_checked: false,
ner_score: 0.0,
ner_entities: []
}
};
}
try {
// Вызываем Natasha API
const response = await $http.post(NATASHA_API_URL, {
text: data.quote,
max_length: 5000
});
const nerResult = response.data;
// Оценка NER в зависимости от критерия
let nerScore = 0.0;
let nerEntities = [];
if (criterionId === 1) {
// Критерий 1: Ищем организации
if (nerResult.has_organizations && nerResult.organizations.length > 0) {
nerScore = 1.0;
nerEntities = nerResult.organizations;
}
} else if (criterionId === 2) {
// Критерий 2: Ищем локации/адреса
if (nerResult.has_locations && nerResult.locations.length > 0) {
nerScore = 1.0;
nerEntities = nerResult.locations;
}
}
// Комбинируем с результатами регулярок
const regexScore = parseFloat(data.score) || 0.0;
const finalScore = Math.max(regexScore, nerScore);
return {
json: {
...data,
ner_checked: true,
ner_score: nerScore,
ner_entities: nerEntities,
ner_organizations: nerResult.organizations || [],
ner_persons: nerResult.persons || [],
ner_locations: nerResult.locations || [],
final_score: finalScore,
method: finalScore === nerScore ? 'Natasha NER' :
finalScore === regexScore ? 'Регулярные выражения' :
'Гибрид (Regex + NER)'
}
};
} catch (error) {
console.error(`Ошибка Natasha API для критерия ${criterionId}:`, error.message);
// Если API не доступен - возвращаем без NER
return {
json: {
...data,
ner_checked: false,
ner_score: 0.0,
ner_entities: [],
ner_error: error.message
}
};
}
}));
return results;