Files
mkd/backend/reviewApiService.js

140 lines
5.4 KiB
JavaScript
Raw Permalink Normal View History

2026-02-04 00:17:04 +05:00
/**
* Сервис загрузки отзывов через API (2ГИС, Яндекс).
* Без парсинга страниц только HTTP-запросы к API.
*/
let axios;
try {
axios = require('axios');
} catch (err) {
console.warn('[reviewApiService] axios не установлен. Установите: npm install axios');
}
const API_2GIS_BASE = 'https://catalog.api.2gis.com/3.0/items';
/**
* Извлечь firm_id из url_template или settings.
* @param {string} urlTemplate - URL вида https://2gis.ru/ufa/firm/2393065583658695/tab/reviews
* @param {object} settings - объект settings из parsing_settings (может содержать firm_id)
* @returns {string|null}
*/
function extractFirmId(urlTemplate, settings) {
if (settings && settings.firm_id) {
return String(settings.firm_id).trim();
}
if (urlTemplate && typeof urlTemplate === 'string') {
const match = urlTemplate.match(/\/firm\/(\d+)(?:\/|$)/);
if (match) return match[1];
}
return null;
}
/**
* Загрузка отзывов из API 2ГИС.
* По документации доступна сводка (reviews_summary: рейтинг 05, количество отзывов).
* Полный список текстов отзывов по отдельному согласованию с 2ГИС.
* @param {object} settings - запись из parsing_settings (url_template, api_key, settings)
* @returns {Promise<Array<{ author_name, text, rating, date, source_url, building_id }>>}
*/
async function fetchFrom2GIS(settings) {
const reviews = [];
if (!axios) {
console.warn('[reviewApiService] axios недоступен');
return reviews;
}
const firmId = extractFirmId(settings.url_template, settings.settings);
if (!firmId) {
console.warn('[reviewApiService] 2ГИС: не удалось извлечь firm_id из URL или settings');
return reviews;
}
const apiKey = (settings.api_key || '').trim();
if (!apiKey) {
console.warn('[reviewApiService] 2ГИС: api_key не задан');
return reviews;
}
const urlTemplate = (settings.url_template || '').trim() || `https://2gis.ru/firm/${firmId}`;
const buildingId = (settings.settings && settings.settings.building_id) || null;
try {
const url = `${API_2GIS_BASE}?id=${encodeURIComponent(firmId)}&key=${encodeURIComponent(apiKey)}&fields=items.reviews_summary,items.address,items.name&locale=ru_RU`;
const response = await axios.get(url, { timeout: 15000 });
if (response.status !== 200) {
console.warn('[reviewApiService] 2ГИС: ответ', response.status);
return reviews;
}
const data = response.data;
const items = (data && data.result && data.result.items) || [];
if (items.length === 0) {
console.warn('[reviewApiService] 2ГИС: объект не найден или пустой items');
return reviews;
}
const item = items[0];
const summary = item.reviews_summary;
const name = item.name || 'Организация';
const addressName = (item.address && item.address.name) || '';
if (summary != null) {
const rating5 = typeof summary.rating === 'number' ? summary.rating : (summary.general_rating ?? 0);
const count = typeof summary.general_review_count === 'number' ? summary.general_review_count : (summary.review_count ?? 0);
const rating10 = Math.max(1, Math.min(10, Math.round(rating5 * 2)));
const today = new Date().toISOString().split('T')[0];
reviews.push({
author_name: '2ГИС',
text: `Сводка 2ГИС: рейтинг ${rating5.toFixed(1)}, отзывов ${count}. ${name}${addressName ? `, ${addressName}` : ''}`.substring(0, 5000),
rating: rating10,
date: today,
source_url: urlTemplate,
building_id: buildingId
});
}
console.log(`[reviewApiService] 2ГИС: загружено записей: ${reviews.length}`);
} catch (err) {
if (err.response) {
console.warn('[reviewApiService] 2ГИС API:', err.response.status, err.response.data && (err.response.data.message || err.response.data.error_message || ''));
} else {
console.warn('[reviewApiService] 2ГИС:', err.message);
}
}
return reviews;
}
/**
* Загрузка отзывов из API Яндекса.
* Публичного API отзывов организаций нет возвращаем пустой массив.
*/
async function fetchFromYandex() {
console.log('[reviewApiService] Яндекс: отзывы через API недоступны. Используйте 2ГИС или виджет.');
return [];
}
/**
* Загрузить отзывы из API для указанного источника.
* @param {string} source - '2gis' | 'yandex_maps'
* @param {object} settings - запись из parsing_settings (url_template, api_key, settings)
* @returns {Promise<Array<{ author_name, text, rating, date, source_url, building_id }>>}
*/
async function fetchReviewsFromApi(source, settings) {
if (source === '2gis') {
return fetchFrom2GIS(settings);
}
if (source === 'yandex_maps') {
return fetchFromYandex(settings);
}
console.warn('[reviewApiService] Неизвестный источник:', source);
return [];
}
module.exports = {
fetchReviewsFromApi,
extractFirmId
};