import PocketBase from 'pocketbase';
const PB_URL = 'http://127.0.0.1:8090';
const pb = new PocketBase(PB_URL);
interface Post {
id: string;
title: string;
content: string;
slug: string;
category: string;
draft: boolean;
}
interface AnalysisResult {
title: string;
slug: string;
category: string;
hasClaim: boolean;
hasTakeaway: boolean;
hasPronouns: boolean;
hasProof: boolean;
h2Issues: string[];
problems: string[];
}
function analyzePost(post: Post): AnalysisResult {
const result: AnalysisResult = {
title: post.title,
slug: post.slug,
category: post.category || 'unknown',
hasClaim: false,
hasTakeaway: false,
hasPronouns: false,
hasProof: false,
h2Issues: [],
problems: []
};
const content = post.content || '';
// Check for Claim patterns directly in content (including HTML)
// Look for new first paragraph that starts with Claim-like content
// Check first 1500 chars to catch posts where Claim may have been inserted
const claimPatterns = [
{ pattern: /За\s+\d+/i, name: 'За год' },
{ pattern: /В\s+\d+\s+(год|месяц)/i, name: 'В год/месяц' },
{ pattern: /\d+%/i, name: 'Процент' },
{ pattern: /Вы можете/i, name: 'Вы можете' },
];
const prefix = content.substring(0, 3000);
result.hasClaim = claimPatterns.some(p => p.pattern.test(prefix));
// Proof: contains numbers
const numberPatterns = [/\d+%/g, /\d+\s+(лет|месяцев|дней|тысяч|рублей)/gi];
result.hasProof = numberPatterns.some(p => p.test(content));
// Pronouns check
const pronouns = /\b(мы|наш|наша|наши|их|он|она|оно|этот|эта|эти)\b/gi;
result.hasPronouns = pronouns.test(content);
// Takeaway check
const takeawayPatterns = [
/что\s+делать/i,
/обращайтесь/i,
/позвоните/i,
/закажите/i,
/получите/i,
/напишите/i,
/свяжитесь/i
];
result.hasTakeaway = takeawayPatterns.some(p => p.test(content));
// H2 analysis - check all H2s in content
const h2Matches = content.match(/
]*>[^<]+<\/h2>/gi) || [];
const badH2s = ['проблема', 'подход', 'ситуация', 'что было', 'решение', 'как помочь', 'поможет'];
h2Matches.forEach(h2 => {
const h2Text = h2.toLowerCase();
if (badH2s.some(b => h2Text.includes(b))) {
result.h2Issues.push(h2.replace(/<[^>]+>/g, ''));
}
});
// Collect problems
if (!result.hasClaim) result.problems.push('Нет Claim в первом абзаце');
if (!result.hasTakeaway) result.problems.push('Нет Takeaway');
if (result.hasPronouns) result.problems.push('Есть местоимения');
if (!result.hasProof) result.problems.push('Нет конкретных цифр');
if (result.h2Issues.length > 0) result.problems.push(`Размытые H2: ${result.h2Issues.join(', ')}`);
return result;
}
async function main() {
console.log('📊 Анализ постов блога по методологии Answer Unit\n');
console.log('='.repeat(60));
try {
const postsResult = await pb.collection('posts').getList(1, 500);
const posts = postsResult.items as unknown as Post[];
console.log(`Найдено постов: ${posts.length}\n`);
// Filter for non-draft posts
const activePosts = posts.filter(p => !p.draft);
console.log(`Опубликованных постов: ${activePosts.length}\n`);
const results = activePosts.map(analyzePost);
// Stats
const withClaim = results.filter(r => r.hasClaim).length;
const withTakeaway = results.filter(r => r.hasTakeaway).length;
const withPronouns = results.filter(r => r.hasPronouns).length;
const withProof = results.filter(r => r.hasProof).length;
const withH2Issues = results.filter(r => r.h2Issues.length > 0).length;
const problemCount = results.filter(r => r.problems.length > 0).length;
const n = activePosts.length;
console.log('📈 ОБЩАЯ СТАТИСТИКА:');
console.log('-'.repeat(40));
console.log(` ✓ Есть Claim: ${withClaim}/${n} (${n > 0 ? Math.round(withClaim/n*100) : 0}%)`);
console.log(` ✓ Есть Takeaway: ${withTakeaway}/${n} (${n > 0 ? Math.round(withTakeaway/n*100) : 0}%)`);
console.log(` ✗ Есть местоимения: ${withPronouns}/${n} (${n > 0 ? Math.round(withPronouns/n*100) : 0}%)`);
console.log(` ✓ Есть Proof (цифры): ${withProof}/${n} (${n > 0 ? Math.round(withProof/n*100) : 0}%)`);
console.log(` ✗ Проблемы с H2: ${withH2Issues}/${n}`);
console.log(` ⚠️ Постов с проблемами: ${problemCount}/${n}\n`);
// Problem posts
const problemPosts = results.filter(r => r.problems.length > 0);
if (problemPosts.length > 0) {
console.log('❌ ПОСТЫ С ПРОБЛЕМАМИ:');
console.log('-'.repeat(40));
problemPosts.forEach((r, i) => {
console.log(`\n${i+1}. ${r.title}`);
console.log(` slug: ${r.slug}`);
console.log(` category: ${r.category}`);
r.problems.forEach(p => console.log(` - ${p}`));
});
}
// Good posts
const goodPosts = results.filter(r => r.problems.length === 0);
if (goodPosts.length > 0) {
console.log('\n\n✅ ПОСТЫ БЕЗ ПРОБЛЕМ:');
console.log('-'.repeat(40));
goodPosts.forEach(r => {
console.log(` • ${r.title}`);
});
}
} catch (error) {
console.error('Ошибка:', error);
}
}
main();