/** * Сервис загрузки отзывов через 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: рейтинг 0–5, количество отзывов). * Полный список текстов отзывов — по отдельному согласованию с 2ГИС. * @param {object} settings - запись из parsing_settings (url_template, api_key, settings) * @returns {Promise>} */ 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>} */ 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 };