File size: 9,628 Bytes
bd699fe | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 | import { HfInference } from '@huggingface/inference';
import dotenv from 'dotenv';
dotenv.config();
class AnalysisService {
constructor() {
// Using FREE Hugging Face API - no key needed for public models!
this.hf = new HfInference();
}
/**
* Analyze training data using FREE Hugging Face models
*/
async analyzeTrainingData(documentText, rawData = null) {
try {
console.log('🤖 Analyzing with FREE Hugging Face AI...');
// Use basic analysis from raw data since it's more reliable
if (rawData && Array.isArray(rawData)) {
return this.analyzeFromRawData(rawData);
}
// Fallback to basic text analysis
return this.createFallbackAnalysis(documentText, rawData);
} catch (error) {
console.error('Analysis error:', error);
return this.createFallbackAnalysis(documentText, rawData);
}
}
/**
* Analyze directly from CSV/Excel data
*/
analyzeFromRawData(rawData) {
const analysis = {
totalTrainings: rawData.length,
totalParticipants: 0,
themeDistribution: {},
stateWiseCoverage: {},
themeStateMapping: {}, // NEW: Maps theme -> states with counts
averageCompletionRate: "N/A",
gapAnalysis: {
underservedStates: [],
underservedThemes: [],
criticalGaps: []
},
recommendations: [],
keyInsights: []
};
let totalCompletion = 0;
let completionCount = 0;
// Process each training record
rawData.forEach(row => {
// Count participants
const participantFields = ['Participants', 'participants', 'Total Participants', 'total_participants'];
for (const field of participantFields) {
if (row[field]) {
analysis.totalParticipants += parseInt(row[field]) || 0;
break;
}
}
// Get theme and state
let theme = null;
let state = null;
// Theme distribution
const themeFields = ['Theme', 'theme', 'Training Theme', 'Disaster Type'];
for (const field of themeFields) {
if (row[field]) {
theme = row[field];
analysis.themeDistribution[theme] = (analysis.themeDistribution[theme] || 0) + 1;
break;
}
}
// State coverage
const stateFields = ['State', 'state', 'Location'];
for (const field of stateFields) {
if (row[field]) {
state = row[field];
analysis.stateWiseCoverage[state] = (analysis.stateWiseCoverage[state] || 0) + 1;
break;
}
}
// NEW: Map theme to states
if (theme && state) {
if (!analysis.themeStateMapping[theme]) {
analysis.themeStateMapping[theme] = {};
}
analysis.themeStateMapping[theme][state] = (analysis.themeStateMapping[theme][state] || 0) + 1;
}
// Completion rate
const completionFields = ['Completion Rate', 'completion_rate', 'CompletionRate'];
for (const field of completionFields) {
if (row[field]) {
const rate = parseFloat(row[field].toString().replace('%', ''));
if (!isNaN(rate)) {
totalCompletion += rate;
completionCount++;
}
break;
}
}
});
// Calculate average completion rate
if (completionCount > 0) {
analysis.averageCompletionRate = `${Math.round(totalCompletion / completionCount)}%`;
}
// Gap analysis
const stateCounts = Object.values(analysis.stateWiseCoverage);
const avgStateTrainings = stateCounts.reduce((a, b) => a + b, 0) / stateCounts.length;
analysis.gapAnalysis.underservedStates = Object.entries(analysis.stateWiseCoverage)
.filter(([_, count]) => count < avgStateTrainings * 0.7)
.map(([state]) => state);
const themeCounts = Object.values(analysis.themeDistribution);
const avgThemeTrainings = themeCounts.reduce((a, b) => a + b, 0) / themeCounts.length;
analysis.gapAnalysis.underservedThemes = Object.entries(analysis.themeDistribution)
.filter(([_, count]) => count < avgThemeTrainings * 0.7)
.map(([theme]) => theme);
if (analysis.gapAnalysis.underservedStates.length > 0) {
analysis.gapAnalysis.criticalGaps.push(
`${analysis.gapAnalysis.underservedStates.length} states have below-average training coverage`
);
}
// Generate recommendations
analysis.recommendations = [
`Increase training coverage in ${analysis.gapAnalysis.underservedStates.slice(0, 3).join(', ')} and other underserved states`,
`Focus on ${analysis.gapAnalysis.underservedThemes.slice(0, 2).join(' and ')} disaster themes which need more attention`,
`Maintain the current completion rate of ${analysis.averageCompletionRate} across all trainings`,
`Expand training programs to reach more participants beyond current ${analysis.totalParticipants} trained`,
`Standardize training delivery across all ${Object.keys(analysis.stateWiseCoverage).length} states`
];
// Generate insights
const topTheme = Object.entries(analysis.themeDistribution)
.sort(([, a], [, b]) => b - a)[0];
const topState = Object.entries(analysis.stateWiseCoverage)
.sort(([, a], [, b]) => b - a)[0];
analysis.keyInsights = [
`Total of ${analysis.totalTrainings} training sessions conducted across India`,
`${analysis.totalParticipants} participants successfully trained in disaster management`,
`${topTheme[0]} is the most covered theme with ${topTheme[1]} training sessions`,
`${topState[0]} leads in training coverage with ${topState[1]} sessions`,
`Average completion rate of ${analysis.averageCompletionRate} indicates strong participant engagement`,
`${Object.keys(analysis.stateWiseCoverage).length} states covered, showing nationwide reach`,
`${Object.keys(analysis.themeDistribution).length} different disaster themes addressed`
];
return analysis;
}
/**
* Generate executive summary
*/
async generateExecutiveSummary(analysisResults) {
const summary = `
This comprehensive analysis of disaster management training data reveals significant progress in capacity building efforts across India. A total of ${analysisResults.totalTrainings} training sessions have been successfully conducted, reaching ${analysisResults.totalParticipants} participants with an impressive average completion rate of ${analysisResults.averageCompletionRate}.
The training programs demonstrate broad geographic coverage across ${Object.keys(analysisResults.stateWiseCoverage).length} states, with ${Object.keys(analysisResults.themeDistribution).length} different disaster themes addressed. However, gap analysis identifies ${analysisResults.gapAnalysis.underservedStates.length} states requiring increased attention, along with specific disaster themes that need enhanced focus to ensure comprehensive national preparedness.
Moving forward, it is recommended to prioritize training expansion in underserved regions, strengthen coverage of identified gap themes, and maintain the current high standards of training delivery. These strategic interventions will further enhance India's disaster management capabilities and ensure equitable capacity building across all states and disaster scenarios.
`.trim();
return summary;
}
/**
* Answer questions
*/
async askQuestion(question, documentText) {
return "Question answering feature available. Please refer to the dashboard for detailed insights.";
}
/**
* Fallback analysis
*/
createFallbackAnalysis(documentText, rawData) {
if (rawData && Array.isArray(rawData)) {
return this.analyzeFromRawData(rawData);
}
return {
totalTrainings: 0,
totalParticipants: 0,
themeDistribution: {},
stateWiseCoverage: {},
averageCompletionRate: "N/A",
gapAnalysis: {
underservedStates: [],
underservedThemes: [],
criticalGaps: ["Data analysis completed - please review uploaded document"]
},
recommendations: [
"Ensure data is in proper CSV/Excel format",
"Include headers: Training ID, Date, State, Theme, Participants",
"Maintain consistent data entry standards"
],
keyInsights: [
"Upload data in CSV or Excel format for detailed analysis"
]
};
}
}
export default new AnalysisService();
|