Review API
Review API
Review API для управления отзывами и комментариями с 7 методами для взаимодействия с отзывами покупателей.
Обзор
Review API предоставляет инструменты для управления отзывами покупателей и комментариями продавца. Доступно для продавцов с подпиской Premium Plus.
Основные возможности:
- 💬 Создание и управление комментариями к отзывам
- 📊 Получение статистики по отзывам
- 🔍 Фильтрация отзывов по статусам и рейтингам
- ⚙️ Изменение статусов отзывов
- 📈 Анализ качества обслуживания через отзывы
- 🎯 Повышение лояльности клиентов
Требования: Подписка Premium Plus
Доступные методы
Управление комментариями
createComment(request) - Оставить комментарий на отзыв
const comment = await reviewApi.createComment({
review_id: 'review-123',
text: 'Спасибо за отзыв!',
mark_review_as_processed: true
});
deleteComment(request) - Удалить комментарий
const result = await reviewApi.deleteComment({
comment_id: 'comment-123'
});
getCommentList(request) - Список комментариев на отзыв
const comments = await reviewApi.getCommentList({
review_id: 'review-123',
limit: 50
});
Управление отзывами
getInfo(request) - Информация об отзыве
const review = await reviewApi.getInfo({
review_id: 'review-123'
});
getList(request?) - Список отзывов
const reviews = await reviewApi.getList({
limit: 100,
status: 'UNPROCESSED'
});
changeStatus(request) - Изменить статус отзывов
const result = await reviewApi.changeStatus({
review_ids: ['review-123', 'review-456'],
status: 'PROCESSED'
});
Аналитика отзывов
getCount(request?) - Количество отзывов по статусам
const counts = await reviewApi.getCount();
TypeScript интерфейсы
// Основные запросы
interface CommentCreateRequest {
review_id: string;
text: string;
mark_review_as_processed?: boolean;
}
interface CommentDeleteRequest {
comment_id: string;
}
interface CommentListRequest {
review_id: string;
limit?: number;
last_id?: string;
sort_dir?: "ASC" | "DESC";
}
interface ReviewChangeStatusRequest {
review_ids: string[];
status: "PROCESSED" | "UNPROCESSED";
}
interface ReviewCountRequest {
// Пустой объект
}
interface ReviewInfoRequest {
review_id: string;
}
interface ReviewListRequest {
limit?: number;
last_id?: string;
status?: "PROCESSED" | "UNPROCESSED";
rating?: 1 | 2 | 3 | 4 | 5;
sort_dir?: "ASC" | "DESC";
date_from?: string;
date_to?: string;
}
// Ответы
interface CommentCreateResponse {
comment_id: string;
result: "ok" | "error";
}
interface CommentDeleteResponse {
result: "ok" | "error";
}
interface CommentListResponse {
comments: Array<{
comment_id: string;
text: string;
author_name: string;
is_owner: boolean;
created_at: string;
updated_at: string;
status: "MODERATED" | "PENDING" | "REJECTED";
}>;
total: number;
has_next: boolean;
last_id?: string;
}
interface ReviewChangeStatusResponse {
result: "ok" | "error";
processed_count?: number;
}
interface ReviewCountResponse {
total: number;
processed: number;
unprocessed: number;
with_photos: number;
with_videos: number;
by_rating: {
"1": number;
"2": number;
"3": number;
"4": number;
"5": number;
};
}
interface ReviewInfoResponse {
review_id: string;
text: string;
rating: 1 | 2 | 3 | 4 | 5;
author_name: string;
status: "PROCESSED" | "UNPROCESSED";
created_at: string;
updated_at: string;
product_id: number;
product_name: string;
sku: number;
photos_amount: number;
videos_amount: number;
photos?: Array<{
url: string;
thumbnail_url: string;
}>;
videos?: Array<{
url: string;
thumbnail_url: string;
duration: number;
}>;
advantages?: string;
disadvantages?: string;
comment?: string;
helpful_votes: number;
not_helpful_votes: number;
is_verified_purchase: boolean;
purchase_date?: string;
}
interface ReviewListResponse {
reviews: Array<{
review_id: string;
text: string;
rating: 1 | 2 | 3 | 4 | 5;
author_name: string;
status: "PROCESSED" | "UNPROCESSED";
created_at: string;
updated_at: string;
product_id: number;
product_name: string;
sku: number;
photos_amount: number;
videos_amount: number;
has_comment: boolean;
helpful_votes: number;
not_helpful_votes: number;
is_verified_purchase: boolean;
}>;
total: number;
has_next: boolean;
last_id?: string;
}
Примеры использования
Обработка новых отзывов
// Получение статистики по отзывам
const reviewStats = await reviewApi.getCount();
console.log("=== Статистика отзывов ===");
console.log(`Всего отзывов: ${reviewStats.total}`);
console.log(`Обработанных: ${reviewStats.processed}`);
console.log(`Необработанных: ${reviewStats.unprocessed}`);
console.log(`С фотографиями: ${reviewStats.with_photos}`);
console.log(`С видео: ${reviewStats.with_videos}`);
console.log("\nРаспределение по рейтингам:");
Object.entries(reviewStats.by_rating).forEach(([rating, count]) => {
const percentage = reviewStats.total > 0 ? (count / reviewStats.total * 100).toFixed(1) : '0';
console.log(`${rating}⭐: ${count} отзывов (${percentage}%)`);
});
// Анализ необходимости обработки
if (reviewStats.unprocessed > 0) {
console.log(`\n⚠️ Требует внимания: ${reviewStats.unprocessed} необработанных отзывов`);
// Получение новых отзывов
const newReviews = await reviewApi.getList({
status: 'UNPROCESSED',
limit: 50,
sort_dir: 'DESC'
});
console.log(`\nПоследние необработанные отзывы:`);
for (const review of newReviews.reviews.slice(0, 10)) {
console.log(`\n${review.rating}⭐ ${review.product_name}`);
console.log(`Автор: ${review.author_name}`);
console.log(`Дата: ${review.created_at}`);
console.log(`Текст: ${review.text.substring(0, 200)}${review.text.length > 200 ? '...' : ''}`);
if (review.photos_amount > 0) {
console.log(`📷 Фото: ${review.photos_amount}`);
}
if (review.videos_amount > 0) {
console.log(`🎥 Видео: ${review.videos_amount}`);
}
// Получение детальной информации при необходимости
if (review.rating <= 2) {
const detailedReview = await reviewApi.getInfo({
review_id: review.review_id
});
console.log(`⚠️ Негативный отзыв - требует ответа`);
if (detailedReview.disadvantages) {
console.log(`Недостатки: ${detailedReview.disadvantages}`);
}
// Создание ответа на негативный отзыв
if (!review.has_comment) {
const response = generateResponseForNegativeReview(detailedReview);
await reviewApi.createComment({
review_id: review.review_id,
text: response,
mark_review_as_processed: true
});
console.log(`✅ Ответ создан и отзыв отмечен как обработанный`);
}
}
}
}
function generateResponseForNegativeReview(review: any): string {
const responses = [
`Благодарим за отзыв! Мы внимательно изучили ваши замечания и обязательно учтем их в работе. Если у вас есть вопросы, обращайтесь к нам напрямую.`,
`Спасибо за обратную связь! Нам важно мнение каждого покупателя. Мы работаем над устранением указанных недостатков.`,
`Приносим извинения за возникшие неудобства. Ваш отзыв поможет нам улучшить качество товаров и сервиса.`
];
// Выбираем ответ в зависимости от рейтинга
return responses[Math.min(review.rating - 1, responses.length - 1)];
}
Управление комментариями
// Получение отзыва с комментариями
const reviewId = 'review-123';
const reviewInfo = await reviewApi.getInfo({ review_id: reviewId });
console.log(`\n=== Отзыв ${reviewId} ===`);
console.log(`Товар: ${reviewInfo.product_name}`);
console.log(`Рейтинг: ${reviewInfo.rating}⭐`);
console.log(`Автор: ${reviewInfo.author_name}`);
console.log(`Подтвержденная покупка: ${reviewInfo.is_verified_purchase ? 'Да' : 'Нет'}`);
console.log(`Текст: ${reviewInfo.text}`);
if (reviewInfo.advantages) {
console.log(`Достоинства: ${reviewInfo.advantages}`);
}
if (reviewInfo.disadvantages) {
console.log(`Недостатки: ${reviewInfo.disadvantages}`);
}
console.log(`Полезность: ${reviewInfo.helpful_votes} 👍 / ${reviewInfo.not_helpful_votes} 👎`);
// Получение комментариев к отзыву
const comments = await reviewApi.getCommentList({
review_id: reviewId,
limit: 20
});
if (comments.comments.length > 0) {
console.log(`\nКомментарии (${comments.total}):`);
comments.comments.forEach(comment => {
const authorType = comment.is_owner ? 'Продавец' : 'Покупатель';
const statusIcon = comment.status === 'MODERATED' ? '✅' :
comment.status === 'PENDING' ? '⏳' : '❌';
console.log(`\n${statusIcon} ${authorType}: ${comment.author_name}`);
console.log(`Дата: ${comment.created_at}`);
console.log(`Текст: ${comment.text}`);
});
// Удаление неудачного комментария (если нужно)
const badComment = comments.comments.find(c =>
c.is_owner && c.text.includes('ошибка')
);
if (badComment) {
console.log(`\n🗑️ Удаляем неудачный комментарий: ${badComment.comment_id}`);
const deleteResult = await reviewApi.deleteComment({
comment_id: badComment.comment_id
});
if (deleteResult.result === 'ok') {
console.log('✅ Комментарий удален');
// Создаем новый, исправленный комментарий
const newComment = await reviewApi.createComment({
review_id: reviewId,
text: 'Благодарим за ваш отзыв! Мы ценим обратную связь от наших клиентов.',
mark_review_as_processed: true
});
console.log(`✅ Создан исправленный комментарий: ${newComment.comment_id}`);
}
}
} else {
console.log('\nКомментариев пока нет');
// Автоматический ответ на положительные отзывы
if (reviewInfo.rating >= 4) {
const thankYouComment = await reviewApi.createComment({
review_id: reviewId,
text: 'Спасибо за положительную оценку! Нам приятно, что вы довольны покупкой. 😊',
mark_review_as_processed: true
});
console.log(`✅ Создан благодарственный комментарий: ${thankYouComment.comment_id}`);
}
}
Массовая обработка отзывов
// Получение всех отзывов за определенный период
const lastMonth = new Date();
lastMonth.setMonth(lastMonth.getMonth() - 1);
let allReviews: any[] = [];
let lastId: string | undefined;
do {
const response = await reviewApi.getList({
limit: 200,
last_id: lastId,
date_from: lastMonth.toISOString(),
sort_dir: 'DESC'
});
allReviews.push(...response.reviews);
lastId = response.has_next ? response.last_id : undefined;
console.log(`Загружено отзывов: ${allReviews.length}`);
} while (lastId);
console.log(`\n=== Анализ ${allReviews.length} отзывов за месяц ===`);
// Анализ по рейтингам
const ratingAnalysis = allReviews.reduce((acc, review) => {
acc[review.rating] = (acc[review.rating] || 0) + 1;
return acc;
}, {} as Record<number, number>);
console.log('\nРаспределение по рейтингам:');
Object.entries(ratingAnalysis).forEach(([rating, count]) => {
const percentage = (count / allReviews.length * 100).toFixed(1);
console.log(`${rating}⭐: ${count} отзывов (${percentage}%)`);
});
// Средний рейтинг
const avgRating = allReviews.reduce((sum, review) => sum + review.rating, 0) / allReviews.length;
console.log(`\nСредний рейтинг: ${avgRating.toFixed(2)}⭐`);
// Анализ отзывов без ответов
const reviewsWithoutComments = allReviews.filter(review => !review.has_comment);
console.log(`\nОтзывы без ответов: ${reviewsWithoutComments.length} (${(reviewsWithoutComments.length / allReviews.length * 100).toFixed(1)}%)`);
// Приоритеты для ответов
const priorityReviews = reviewsWithoutComments
.filter(review => review.rating <= 3 || review.photos_amount > 0)
.sort((a, b) => a.rating - b.rating); // сначала самые низкие оценки
console.log(`\nПриоритетных отзывов для ответа: ${priorityReviews.length}`);
// Массовая обработка приоритетных отзывов
const reviewsToProcess: string[] = [];
for (const review of priorityReviews.slice(0, 20)) { // обрабатываем максимум 20 за раз
try {
let responseText: string;
if (review.rating <= 2) {
responseText = `Приносим извинения за возникшие неудобства с товаром "${review.product_name}". Мы внимательно изучили ваш отзыв и обязательно учтем замечания. Обращайтесь к нам при любых вопросах!`;
} else if (review.rating === 3) {
responseText = `Благодарим за честную оценку товара "${review.product_name}". Ваша обратная связь помогает нам становиться лучше. Будем рады видеть вас среди наших покупателей снова!`;
} else if (review.photos_amount > 0) {
responseText = `Спасибо за подробный отзыв с фотографиями! Это очень помогает другим покупателям сделать правильный выбор. 📷✨`;
} else {
responseText = `Благодарим за ваш отзыв! Нам важно мнение каждого покупателя. 😊`;
}
await reviewApi.createComment({
review_id: review.review_id,
text: responseText,
mark_review_as_processed: true
});
reviewsToProcess.push(review.review_id);
// Пауза между запросами
await new Promise(resolve => setTimeout(resolve, 1000));
} catch (error) {
console.error(`Ошибка при ответе на отзыв ${review.review_id}:`, error);
}
}
console.log(`✅ Обработано отзывов: ${reviewsToProcess.length}`);
Аналитика товаров по отзывам
// Анализ отзывов по товарам
const productReviews = new Map<number, {
product_name: string;
reviews: any[];
avg_rating: number;
total_photos: number;
total_videos: number;
response_rate: number;
}>();
allReviews.forEach(review => {
if (!productReviews.has(review.product_id)) {
productReviews.set(review.product_id, {
product_name: review.product_name,
reviews: [],
avg_rating: 0,
total_photos: 0,
total_videos: 0,
response_rate: 0
});
}
const productData = productReviews.get(review.product_id)!;
productData.reviews.push(review);
productData.total_photos += review.photos_amount;
productData.total_videos += review.videos_amount;
});
// Расчет метрик для каждого товара
productReviews.forEach(productData => {
productData.avg_rating = productData.reviews.reduce((sum, r) => sum + r.rating, 0) / productData.reviews.length;
productData.response_rate = productData.reviews.filter(r => r.has_comment).length / productData.reviews.length;
});
// Топ товаров по количеству отзывов
const topReviewedProducts = Array.from(productReviews.entries())
.sort((a, b) => b[1].reviews.length - a[1].reviews.length)
.slice(0, 10);
console.log('\n=== Топ-10 товаров по отзывам ===');
topReviewedProducts.forEach(([productId, data], index) => {
console.log(`\n${index + 1}. ${data.product_name}`);
console.log(` Отзывов: ${data.reviews.length}`);
console.log(` Средний рейтинг: ${data.avg_rating.toFixed(2)}⭐`);
console.log(` Процент ответов: ${(data.response_rate * 100).toFixed(1)}%`);
console.log(` Фото: ${data.total_photos}, Видео: ${data.total_videos}`);
});
// Товары с низким рейтингом, требующие внимания
const problematicProducts = Array.from(productReviews.entries())
.filter(([, data]) => data.avg_rating < 3.5 && data.reviews.length >= 5)
.sort((a, b) => a[1].avg_rating - b[1].avg_rating);
if (problematicProducts.length > 0) {
console.log('\n⚠️ === Товары с низким рейтингом ===');
problematicProducts.forEach(([productId, data]) => {
console.log(`\n❌ ${data.product_name}`);
console.log(` Рейтинг: ${data.avg_rating.toFixed(2)}⭐ (${data.reviews.length} отзывов)`);
console.log(` Процент ответов: ${(data.response_rate * 100).toFixed(1)}%`);
// Анализ негативных отзывов
const negativeReviews = data.reviews.filter(r => r.rating <= 2);
if (negativeReviews.length > 0) {
console.log(` Негативных отзывов: ${negativeReviews.length}`);
console.log(` Требует срочного улучшения качества или замены`);
}
});
}
Сложные сценарии
ReviewManagementSystem - Система управления отзывами
class ReviewManagementSystem {
constructor(private api: ReviewApi) {}
async runDailyReviewProcessing(): Promise<ReviewProcessingReport> {
console.log('🔄 Запуск ежедневной обработки отзывов...');
// 1. Получение статистики
const currentStats = await this.api.getCount();
// 2. Обработка критически важных отзывов
const criticalReviews = await this.processCriticalReviews();
// 3. Автоматические ответы на типовые отзывы
const automaticResponses = await this.generateAutomaticResponses();
// 4. Анализ трендов и качества
const qualityAnalysis = await this.analyzeQualityTrends();
// 5. Генерация рекомендаций
const recommendations = this.generateActionableRecommendations(qualityAnalysis);
return {
processing_date: new Date().toISOString(),
initial_stats: currentStats,
critical_reviews_processed: criticalReviews.processed_count,
automatic_responses_created: automaticResponses.responses_count,
quality_analysis: qualityAnalysis,
recommendations,
final_stats: await this.api.getCount()
};
}
private async processCriticalReviews(): Promise<CriticalProcessingResult> {
// Критические отзывы: 1-2 звезды с фото/видео за последние 24 часа
const yesterday = new Date(Date.now() - 24 * 60 * 60 * 1000);
const lowRatingReviews = await this.api.getList({
rating: 1,
date_from: yesterday.toISOString(),
status: 'UNPROCESSED',
limit: 100
});
const veryLowRatingReviews = await this.api.getList({
rating: 2,
date_from: yesterday.toISOString(),
status: 'UNPROCESSED',
limit: 100
});
const allCriticalReviews = [...lowRatingReviews.reviews, ...veryLowRatingReviews.reviews];
// Приоритезируем отзывы с медиа-контентом
const criticalWithMedia = allCriticalReviews.filter(review =>
review.photos_amount > 0 || review.videos_amount > 0
);
let processedCount = 0;
const urgentResponses: string[] = [];
for (const review of criticalWithMedia) {
// Получаем детальную информацию
const detailedReview = await this.api.getInfo({
review_id: review.review_id
});
// Создаем персонализированный ответ
const response = this.generateCriticalResponse(detailedReview);
await this.api.createComment({
review_id: review.review_id,
text: response,
mark_review_as_processed: true
});
urgentResponses.push(review.review_id);
processedCount++;
// Rate limiting
await new Promise(resolve => setTimeout(resolve, 2000));
}
return {
processed_count: processedCount,
urgent_responses_created: urgentResponses.length,
review_ids: urgentResponses
};
}
private generateCriticalResponse(review: any): string {
const productName = review.product_name;
const hasPhotos = review.photos_amount > 0;
const hasVideos = review.videos_amount > 0;
let response = `Благодарим за подробный отзыв о товаре "${productName}". `;
if (hasPhotos || hasVideos) {
response += `Мы внимательно изучили приложенные материалы и `;
}
response += `серьезно отнесемся к вашим замечаниям. Наша команда проанализирует указанные проблемы `;
response += `и примет меры для их устранения. `;
if (review.disadvantages) {
response += `Особое внимание будет уделено вопросам, которые вы отметили в недостатках. `;
}
response += `Мы ценим честную обратную связь и используем её для улучшения качества наших товаров. `;
response += `При возникновении дополнительных вопросов обращайтесь к нам напрямую.`;
return response;
}
private async analyzeQualityTrends(): Promise<QualityAnalysis> {
// Получение отзывов за последние 30 дней
const thirtyDaysAgo = new Date(Date.now() - 30 * 24 * 60 * 60 * 1000);
const recentReviews = await this.getAllReviewsForPeriod(
thirtyDaysAgo.toISOString(),
new Date().toISOString()
);
// Анализ трендов рейтинга
const ratingTrend = this.calculateRatingTrend(recentReviews);
// Анализ скорости ответов
const responseSpeedAnalysis = this.analyzeResponseSpeed(recentReviews);
// Анализ качества ответов
const responseQualityAnalysis = await this.analyzeResponseQuality(recentReviews);
return {
period: '30 days',
total_reviews: recentReviews.length,
average_rating: recentReviews.reduce((sum, r) => sum + r.rating, 0) / recentReviews.length,
rating_trend: ratingTrend,
response_rate: recentReviews.filter(r => r.has_comment).length / recentReviews.length,
response_speed: responseSpeedAnalysis,
response_quality: responseQualityAnalysis,
media_engagement: {
reviews_with_photos: recentReviews.filter(r => r.photos_amount > 0).length,
reviews_with_videos: recentReviews.filter(r => r.videos_amount > 0).length,
total_media_reviews: recentReviews.filter(r => r.photos_amount > 0 || r.videos_amount > 0).length
}
};
}
private generateActionableRecommendations(analysis: QualityAnalysis): ReviewRecommendation[] {
const recommendations: ReviewRecommendation[] = [];
// Анализ среднего рейтинга
if (analysis.average_rating < 4.0) {
recommendations.push({
category: 'QUALITY_IMPROVEMENT',
priority: 'HIGH',
title: 'Низкий средний рейтинг',
description: `Средний рейтинг составляет ${analysis.average_rating.toFixed(2)} звезд`,
actions: [
'Проанализировать основные причины негативных отзывов',
'Улучшить качество товаров с низким рейтингом',
'Усилить контроль качества'
],
expected_impact: 'Повышение среднего рейтинга на 0.3-0.5 звезд'
});
}
// Анализ скорости ответов
if (analysis.response_rate < 0.8) {
recommendations.push({
category: 'RESPONSE_RATE',
priority: 'MEDIUM',
title: 'Низкий процент ответов на отзывы',
description: `Процент ответов составляет ${(analysis.response_rate * 100).toFixed(1)}%`,
actions: [
'Настроить автоматические ответы на типовые отзывы',
'Увеличить частоту проверки новых отзывов',
'Создать шаблоны ответов для разных ситуаций'
],
expected_impact: 'Увеличение процента ответов до 90%+'
});
}
// Анализ медиа-контента
const mediaRate = analysis.media_engagement.total_media_reviews / analysis.total_reviews;
if (mediaRate > 0.3) {
recommendations.push({
category: 'MEDIA_ENGAGEMENT',
priority: 'LOW',
title: 'Высокая доля отзывов с медиа-контентом',
description: `${(mediaRate * 100).toFixed(1)}% отзывов содержат фото или видео`,
actions: [
'Поощрять покупателей оставлять отзывы с фото',
'Использовать медиа-контент в маркетинге',
'Благодарить за подробные отзывы с фото/видео'
],
expected_impact: 'Увеличение вовлеченности и доверия покупателей'
});
}
return recommendations.sort((a, b) => {
const priorityOrder = { 'HIGH': 3, 'MEDIUM': 2, 'LOW': 1 };
return priorityOrder[b.priority] - priorityOrder[a.priority];
});
}
}
interface ReviewProcessingReport {
processing_date: string;
initial_stats: ReviewCountResponse;
critical_reviews_processed: number;
automatic_responses_created: number;
quality_analysis: QualityAnalysis;
recommendations: ReviewRecommendation[];
final_stats: ReviewCountResponse;
}
interface QualityAnalysis {
period: string;
total_reviews: number;
average_rating: number;
rating_trend: TrendData;
response_rate: number;
response_speed: ResponseSpeedData;
response_quality: ResponseQualityData;
media_engagement: MediaEngagementData;
}
interface ReviewRecommendation {
category: 'QUALITY_IMPROVEMENT' | 'RESPONSE_RATE' | 'MEDIA_ENGAGEMENT' | 'CUSTOMER_SERVICE';
priority: 'HIGH' | 'MEDIUM' | 'LOW';
title: string;
description: string;
actions: string[];
expected_impact: string;
}
AutomatedResponseEngine - Генератор автоматических ответов
class AutomatedResponseEngine {
private responseTemplates = new Map<string, ResponseTemplate>([
['positive_high', {
condition: (review: any) => review.rating >= 5,
templates: [
'Благодарим за отличную оценку! Нам очень приятно, что товар полностью оправдал ваши ожидания! 🌟',
'Спасибо за 5 звезд! Такие отзывы вдохновляют нас работать еще лучше! ⭐⭐⭐⭐⭐',
'Ваша высокая оценка - лучшая награда для нашей команды! Благодарим за доверие! 😊'
]
}],
['positive_with_photo', {
condition: (review: any) => review.rating >= 4 && review.photos_amount > 0,
templates: [
'Спасибо за подробный отзыв с фотографиями! Это очень помогает другим покупателям! 📷✨',
'Благодарим за отличные фото! Ваш отзыв поможет другим сделать правильный выбор! 📸',
'Отличные фотографии! Спасибо, что делитесь опытом с другими покупателями! 🤳'
]
}],
['neutral_constructive', {
condition: (review: any) => review.rating === 3,
templates: [
'Благодарим за честную оценку! Ваше мнение помогает нам становиться лучше!',
'Спасибо за обратную связь! Мы учтем ваши замечания в нашей работе!',
'Ценим ваше мнение! Постараемся оправдать ваши ожидания в следующий раз!'
]
}]
]);
async generateContextualResponse(review: any): Promise<string | null> {
// Поиск подходящего шаблона
for (const [templateKey, template] of this.responseTemplates) {
if (template.condition(review)) {
const randomTemplate = template.templates[
Math.floor(Math.random() * template.templates.length)
];
// Персонализация ответа
return this.personalizeResponse(randomTemplate, review);
}
}
return null;
}
private personalizeResponse(template: string, review: any): string {
let response = template;
// Добавляем упоминание товара для важных отзывов
if (review.rating <= 2 || review.photos_amount > 0) {
response = response.replace('товар', `товар "${review.product_name}"`);
}
// Добавляем благодарность за детали
if (review.text.length > 200) {
response += ' Спасибо за подробности!';
}
return response;
}
}
interface ResponseTemplate {
condition: (review: any) => boolean;
templates: string[];
}
Обработка ошибок
try {
const comment = await reviewApi.createComment({
review_id: 'review-123',
text: 'Спасибо за отзыв!'
});
if (comment.result !== 'ok') {
console.error('Не удалось создать комментарий');
}
} catch (error) {
if (error.response?.status === 403) {
console.error('Недостаточно прав - требуется подписка Premium Plus');
} else if (error.response?.status === 404) {
console.error('Отзыв не найден');
} else if (error.response?.status === 400) {
console.error('Некорректные данные:', error.response.data);
} else {
console.error('Неожиданная ошибка:', error.message);
}
}
Лучшие практики
Стратегия ответов на отзывы
// Система приоритизации ответов
function calculateResponsePriority(review: any): number {
let priority = 0;
// Рейтинг (чем ниже, тем выше приоритет)
priority += (6 - review.rating) * 20;
// Наличие медиа-контента
if (review.photos_amount > 0) priority += 15;
if (review.videos_amount > 0) priority += 10;
// Длина отзыва (подробные отзывы важнее)
if (review.text.length > 300) priority += 10;
// Новизна (свежие отзывы важнее)
const daysOld = (Date.now() - new Date(review.created_at).getTime()) / (1000 * 60 * 60 * 24);
if (daysOld < 3) priority += 15;
return priority;
}
// Автоматическая категоризация отзывов
function categorizeReview(review: any): ReviewCategory {
const text = review.text.toLowerCase();
if (text.includes('доставка') || text.includes('упаковка')) {
return 'LOGISTICS';
} else if (text.includes('качество') || text.includes('дефект')) {
return 'QUALITY';
} else if (text.includes('размер') || text.includes('цвет')) {
return 'SPECIFICATIONS';
} else if (text.includes('цена') || text.includes('стоимость')) {
return 'PRICING';
} else {
return 'GENERAL';
}
}
type ReviewCategory = 'LOGISTICS' | 'QUALITY' | 'SPECIFICATIONS' | 'PRICING' | 'GENERAL';
Мониторинг качества ответов
// Анализ эффективности ответов
class ResponseQualityAnalyzer {
async analyzeResponseImpact(reviewId: string): Promise<ResponseImpact> {
// Получение отзыва до и после ответа
const review = await reviewApi.getInfo({ review_id: reviewId });
const comments = await reviewApi.getCommentList({
review_id: reviewId,
limit: 10
});
const sellerComments = comments.comments.filter(c => c.is_owner);
if (sellerComments.length === 0) {
return { has_response: false, impact_score: 0 };
}
// Анализ полезности отзыва
const helpfulnessRatio = review.helpful_votes /
Math.max(1, review.helpful_votes + review.not_helpful_votes);
return {
has_response: true,
response_count: sellerComments.length,
response_quality_score: this.assessResponseQuality(sellerComments[0].text),
helpfulness_ratio: helpfulnessRatio,
impact_score: this.calculateImpactScore(review, sellerComments[0])
};
}
private assessResponseQuality(responseText: string): number {
let score = 50; // базовый балл
// Длина ответа
if (responseText.length > 100) score += 10;
if (responseText.length > 200) score += 10;
// Персонализация
if (responseText.includes('товар') || responseText.includes('покупк')) score += 15;
// Эмпатия и благодарность
if (responseText.includes('спасибо') || responseText.includes('благодар')) score += 10;
if (responseText.includes('извин') || responseText.includes('сожале')) score += 15;
// Конструктивность
if (responseText.includes('учтем') || responseText.includes('улучш')) score += 10;
return Math.min(100, score);
}
}
interface ResponseImpact {
has_response: boolean;
response_count?: number;
response_quality_score?: number;
helpfulness_ratio?: number;
impact_score: number;
}
Интеграционные заметки
- Premium Plus Required: API доступно только для подписчиков Premium Plus
- Rate Limiting: API поддерживает до 200 запросов в минуту
- Moderation: Все комментарии проходят модерацию перед публикацией
- Response Time: Рекомендуется отвечать на отзывы в течение 48 часов
- Character Limits: Комментарии ограничены 3000 символами
- Media Support: API предоставляет информацию о фото и видео в отзывах
- Status Tracking: Система отслеживает статусы обработки отзывов
- Analytics Integration: Данные интегрируются с общей аналитикой продавца