Tech4biz-channel/Channel-Backend/scripts/normalize-data.ts

149 lines
6.9 KiB
TypeScript

import dotenv from 'dotenv';
dotenv.config();
import prisma from '../src/utils/db';
const INITIAL_VERTICALS = [
{ name: 'Cybersecurity', slug: 'cybersecurity', icon: 'Shield', color: '#ef4444', description: 'OT, Infrastructure & Data Defense' },
{ name: 'AI & ML', slug: 'ai-ml', icon: 'Cpu', color: '#8b5cf6', description: 'Artificial Intelligence & Machine Learning' },
{ name: 'Healthcare & Pharma', slug: 'healthcare-pharma', icon: 'Activity', color: '#ec4899', description: 'Medical, Diagnostics & BioTech' },
{ name: 'Finance & Banking', slug: 'finance-banking', icon: 'Landmark', color: '#10b981', description: 'FinTech, Payments & Risk Analytics' },
{ name: 'Insurance', slug: 'insurance', icon: 'FileCheck', color: '#3b82f6', description: 'InsurTech, Claims & Underwriting' },
{ name: 'Energy & Utilities', slug: 'energy-utilities', icon: 'Zap', color: '#f59e0b', description: 'Smart Grid, Power & Renewables' },
{ name: 'Agriculture', slug: 'agriculture', icon: 'Leaf', color: '#84cc16', description: 'AgriTech, Precision Farming & Supply' },
{ name: 'Education', slug: 'education', icon: 'GraduationCap', color: '#06b6d4', description: 'EdTech, LMS & Institutional Tools' },
{ name: 'Manufacturing & IoT', slug: 'manufacturing-iot', icon: 'Factory', color: '#6366f1', description: 'Industrial Automation & Edge IoT' },
{ name: 'Automotive', slug: 'automotive', icon: 'Car', color: '#14b8a6', description: 'Connected Vehicles & Telematics' },
{ name: 'Retail & Supply Chain', slug: 'retail-supply-chain', icon: 'ShoppingBag', color: '#d97706', description: 'E-Commerce, Logistics & Smart Retail' },
{ name: 'Blockchain', slug: 'blockchain', icon: 'Link', color: '#0284c7', description: 'Smart Contracts & Web3 Infrastructure' },
];
function inferContentType(type: string, subcategory?: string | null): string {
const sub = (subcategory || '').toLowerCase().trim();
if (sub === 'case study') return 'case_study';
if (sub === 'showcase') return 'showcase';
if (sub === 'news letter' || sub === 'marketing milestone') return 'newsletter';
if (sub === 'portfolio' || sub === 'company deck' || sub === 'product showcase' || sub === 'rnd innovation') return 'portfolio';
if (sub === 'mvp') return 'mvp';
if (sub === 'workflow automation' || sub === 'worlflow automation') return 'workflow';
if (sub === 'use case') return 'use_case';
if (sub === 'test drive resources') return 'test_drive';
if (type === 'case_study') return 'case_study';
if (type === 'url') return 'showcase';
if (type.includes('pdf') || type.includes('document') || type.includes('word')) return 'document';
if (type.includes('sheet') || type.includes('csv') || type.includes('excel')) return 'spreadsheet';
if (type.includes('presentation') || type.includes('powerpoint')) return 'presentation';
if (type.includes('image')) return 'image';
return 'document';
}
function matchVerticalSlugs(title: string, description?: string | null): string[] {
const text = `${title} ${description || ''}`.toLowerCase();
const matched = new Set<string>();
if (/cybersecurity|security|threat|ot |defence|defense|ransomware|audit|hacker|firewall|fpga|compliance|kyc|aml/.test(text)) {
matched.add('cybersecurity');
}
if (/ai|machine learning|resnet|densenet|nlp|chatbot|genai|deep learning|prediction|predictive|forecasting|gpt|n8n|rag|speech/.test(text)) {
matched.add('ai-ml');
}
if (/health|medical|pharma|drug|cancer|hospital|patient|doctor|eye|blood|hematology|x-ray|brain tumor|bio|biotech|wearable|ventilator|ct scan/.test(text)) {
matched.add('healthcare-pharma');
}
if (/bank|fintech|payment|fraud|credit|loan|financial|accounting|cash|revenue|investor|audit|trade|b2b/.test(text)) {
matched.add('finance-banking');
}
if (/insurance|claims|underwriting|insurtech|policy|catastrophe|actuary/.test(text)) {
matched.add('insurance');
}
if (/energy|grid|power|renewable|ev |electric vehicle|utility|utilities|battery|charging|power plant|oms|ems|metering|solar|wind/.test(text)) {
matched.add('energy-utilities');
}
if (/agri|farm|crop|livestock|soil|aqua|pest|aquaponics|harvest|yield/.test(text)) {
matched.add('agriculture');
}
if (/education|student|learning|lms|classroom|exam|academic|textbook|proctoring|university|school/.test(text)) {
matched.add('education');
}
if (/manufactur|industrial|iot|edge|predictive maintenance|digital twin|esp32|ble board|pcb|robotics|factory|plc/.test(text)) {
matched.add('manufacturing-iot');
}
if (/vehicle|automotive|fleet|telematics|adas|car|driving|mobility|maas/.test(text)) {
matched.add('automotive');
}
if (/retail|e-commerce|supply chain|inventory|mall|store|basket|procurement|logistics|fmcg|pos/.test(text)) {
matched.add('retail-supply-chain');
}
if (/blockchain|smart contract|credentialing|traceability/.test(text)) {
matched.add('blockchain');
}
return Array.from(matched);
}
async function main() {
console.log('🚀 Starting Data Normalization & Taxonomy Seeding...');
// 1. Seed Verticals
const verticalMap = new Map<string, string>(); // slug -> id
for (const v of INITIAL_VERTICALS) {
const upserted = await prisma.vertical.upsert({
where: { slug: v.slug },
update: { name: v.name, icon: v.icon, color: v.color, description: v.description },
create: v,
});
verticalMap.set(v.slug, upserted.id);
}
console.log(`${verticalMap.size} Verticals ready.`);
// 2. Fix typos in Subcategories
await prisma.asset.updateMany({
where: { subcategory: { in: ['Showcaase', 'showcase'] } },
data: { subcategory: 'Showcase' },
});
await prisma.asset.updateMany({
where: { subcategory: 'Worlflow Automation' },
data: { subcategory: 'Workflow Automation' },
});
await prisma.asset.updateMany({
where: { subcategory: 'Use Case', categoryId: 'Marketing' },
data: { categoryId: 'Technical' },
});
await prisma.asset.updateMany({
where: { subcategory: 'MVP', categoryId: 'Presentations' },
data: { categoryId: 'Resources' },
});
console.log('✅ Subcategory typos & category alignments fixed.');
// 3. Process all assets
const assets = await prisma.asset.findMany();
let updatedCount = 0;
for (const asset of assets) {
const contentType = inferContentType(asset.type, asset.subcategory);
const matchedSlugs = matchVerticalSlugs(asset.title, asset.description);
const verticalIds = matchedSlugs.map(slug => verticalMap.get(slug)).filter(Boolean) as string[];
await prisma.asset.update({
where: { id: asset.id },
data: {
contentType,
verticals: {
set: verticalIds.map(id => ({ id })),
},
},
});
updatedCount++;
}
console.log(`🎉 Successfully normalized ${updatedCount} assets with content types & vertical tags!`);
}
main()
.catch(err => {
console.error('❌ Migration failed:', err);
process.exit(1);
})
.finally(async () => {
await prisma.$disconnect();
});