|
|
@@ -1,14 +1,155 @@
|
|
|
-import { Controller, Get, Logger, UseGuards } from '@nestjs/common';
|
|
|
+/**
|
|
|
+ * * **Current State:** The `AppController` has a simple `getHello()` method and does not contain any seeding logic or master references.
|
|
|
+ * * **Intended Mutation:** We will add a `@Get('seed')` route to `AppController` which injects `PhaseService`, `BlockService`, and `FFBProductionService`. The handler `seedSystemData` will chronologically:
|
|
|
+ * 1. Parse `PhaseData.json`, map the properties, and insert them via `PhaseService.create()`.
|
|
|
+ * 2. Parse `BlockData.json`, map the properties (programmatically appending `phaseCode: "PH01"`), and insert them via `BlockService.create()`.
|
|
|
+ * 3. Parse `FFBProductionData.json`, slice the array to the first 20 elements to prevent API rate-limiting/timeouts, map their properties, and stream each directly to `FFBProductionService.create()` inside `try/catch` blocks.
|
|
|
+ * * **Risk Check:** The Gemini Embedding API can experience throttling, rate-limiting, or timeouts during batch ingestion. We will isolate each record ingestion step inside a localized `try/catch` block, log errors individually, and continue streaming remaining records to guarantee high-resiliency.
|
|
|
+ */
|
|
|
+
|
|
|
+import { Controller, Get, Logger, BadRequestException } from '@nestjs/common';
|
|
|
import { AppService } from './app.service';
|
|
|
+import { PhaseService } from './site/services/phase.service';
|
|
|
+import { BlockService } from './site/services/block.service';
|
|
|
+import { FFBProductionService } from './FFB/services/ffb-production.service';
|
|
|
+import * as fs from 'fs';
|
|
|
|
|
|
@Controller()
|
|
|
export class AppController {
|
|
|
- private logger: Logger = new Logger(`AppController`)
|
|
|
- constructor(private readonly service: AppService) { }
|
|
|
+ private readonly logger: Logger = new Logger('AppController');
|
|
|
+
|
|
|
+ constructor(
|
|
|
+ private readonly service: AppService,
|
|
|
+ private readonly phaseService: PhaseService,
|
|
|
+ private readonly blockService: BlockService,
|
|
|
+ private readonly ffbService: FFBProductionService,
|
|
|
+ ) { }
|
|
|
|
|
|
@Get()
|
|
|
getHello(): string {
|
|
|
return this.service.getHello();
|
|
|
}
|
|
|
|
|
|
+ @Get('seed')
|
|
|
+ async seedSystemData() {
|
|
|
+ this.logger.log('🚀 Starting chronological seeding...');
|
|
|
+
|
|
|
+ // 1. PHASE SEEDING
|
|
|
+ const phaseDataPath = 'e:\\Task\\Research and Development\\RAG\\mongo stuff\\PhaseData.json';
|
|
|
+ if (!fs.existsSync(phaseDataPath)) {
|
|
|
+ throw new BadRequestException('PhaseData.json not found!');
|
|
|
+ }
|
|
|
+ const rawPhases = JSON.parse(fs.readFileSync(phaseDataPath, 'utf8'));
|
|
|
+ this.logger.log(`Found ${rawPhases.length} phases to process.`);
|
|
|
+
|
|
|
+ for (const rawPhase of rawPhases) {
|
|
|
+ try {
|
|
|
+ const mappedPhase = {
|
|
|
+ locId: Number(rawPhase.loc_id),
|
|
|
+ phaseCode: rawPhase.name,
|
|
|
+ description: rawPhase.description,
|
|
|
+ locType: rawPhase.loc_type,
|
|
|
+ };
|
|
|
+ await this.phaseService.create(mappedPhase);
|
|
|
+ } catch (err) {
|
|
|
+ this.logger.error(`Error inserting Phase ${rawPhase.name}: ${err.message}`);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ console.log('[SEED] Phase collection initialization pass complete.');
|
|
|
+
|
|
|
+ // 2. BLOCK SEEDING
|
|
|
+ const blockDataPath = 'e:\\Task\\Research and Development\\RAG\\mongo stuff\\BlockData.json';
|
|
|
+ if (!fs.existsSync(blockDataPath)) {
|
|
|
+ throw new BadRequestException('BlockData.json not found!');
|
|
|
+ }
|
|
|
+ const rawBlocks = JSON.parse(fs.readFileSync(blockDataPath, 'utf8'));
|
|
|
+ this.logger.log(`Found ${rawBlocks.length} blocks to process.`);
|
|
|
+
|
|
|
+ for (const rawBlock of rawBlocks) {
|
|
|
+ try {
|
|
|
+ const mappedBlock = {
|
|
|
+ locId: Number(rawBlock.loc_id),
|
|
|
+ blockCode: rawBlock.blockCode,
|
|
|
+ phaseCode: 'PH01', // Anchor parameter programmatically appended
|
|
|
+ blockDesc: rawBlock.blockDesc,
|
|
|
+ locType: rawBlock.loc_type,
|
|
|
+ entryNo: Number(rawBlock.entry_no),
|
|
|
+ entryYear: Number(rawBlock.entry_year),
|
|
|
+ quarterPlanted: Number(rawBlock.quater_planted),
|
|
|
+ monthPlanted: rawBlock.month_planted,
|
|
|
+ totalTrees: Number(rawBlock.numOfTreesPlanted),
|
|
|
+ totalMaturedTrees: Number(rawBlock.totalTreeMatured),
|
|
|
+ totalImmaturedTrees: Number(rawBlock.totalTreeImmatured),
|
|
|
+ totalDeadTrees: Number(rawBlock.totalTreeDead),
|
|
|
+ plantedArea: Number(rawBlock.totalPlantedArea),
|
|
|
+ initialPlantedArea: Number(rawBlock.initalPlantedArea),
|
|
|
+ plantedLocUOM: rawBlock.plantedLocUOM,
|
|
|
+ soilCondition: rawBlock.loc_soil_condition,
|
|
|
+ };
|
|
|
+ await this.blockService.create(mappedBlock);
|
|
|
+ } catch (err) {
|
|
|
+ this.logger.error(`Error inserting Block ${rawBlock.blockCode}: ${err.message}`);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ console.log('[SEED] Block collection initialization pass complete.');
|
|
|
+
|
|
|
+ // 3. FFB TRANSACTION INGESTION & VECTOR ENRICHMENT STREAM
|
|
|
+ const ffbDataPath = 'e:\\Task\\Research and Development\\RAG\\mongo stuff\\FFBProductionData.json';
|
|
|
+ if (!fs.existsSync(ffbDataPath)) {
|
|
|
+ throw new BadRequestException('FFBProductionData.json not found!');
|
|
|
+ }
|
|
|
+ const rawFfbs = JSON.parse(fs.readFileSync(ffbDataPath, 'utf8'));
|
|
|
+ // Slice to the first 20 records to keep seeding process snappy and safe from rate limit throttling
|
|
|
+ const ffbSubset = rawFfbs.slice(0, 20);
|
|
|
+ this.logger.log(`Streaming first ${ffbSubset.length} FFB Production records for enrichment & embedding...`);
|
|
|
+
|
|
|
+ for (const rawFfb of ffbSubset) {
|
|
|
+ try {
|
|
|
+ const mappedFfb = {
|
|
|
+ productionDate: new Date('2024-01-01'), // default date
|
|
|
+ prjCode: rawFfb.prj_code,
|
|
|
+ actCode: rawFfb.act_code,
|
|
|
+ actName: rawFfb.act_name,
|
|
|
+ entityCode: rawFfb.entitycode,
|
|
|
+ orgnId: rawFfb.orgn_id ? Number(rawFfb.orgn_id) : 0,
|
|
|
+ orgnCode: rawFfb.orgn_code,
|
|
|
+ orgnFullName: rawFfb.orgn_full_name,
|
|
|
+ orgnAddress: rawFfb.orgn_address,
|
|
|
+ orgnCompRegNo: rawFfb.orgn_comp_reg_no,
|
|
|
+ phaseCode: rawFfb.phaseCode || 'PH01',
|
|
|
+ phaseName: rawFfb.phaseName || 'PHASE 01',
|
|
|
+ phaseDesc: rawFfb.phaseDesc || 'PHASE 01',
|
|
|
+ blockCode: rawFfb.blockCode,
|
|
|
+ blockName: rawFfb.blockName || null,
|
|
|
+ blockDesc: rawFfb.blockDesc || null,
|
|
|
+ truckNo: rawFfb.truck_no,
|
|
|
+ millNo: rawFfb.mill_no,
|
|
|
+ actEntryNo: rawFfb.act_entry_no ? Number(rawFfb.act_entry_no) : 0,
|
|
|
+ actRound: rawFfb.act_round ? Number(rawFfb.act_round) : 0,
|
|
|
+ weightChitNo: rawFfb.weight_chit_no,
|
|
|
+ ownNetWeight: rawFfb.own_net_weight ? Number(rawFfb.own_net_weight) : null,
|
|
|
+ netWeight: rawFfb.net_weight ? Number(rawFfb.net_weight) : 0,
|
|
|
+ actUom: rawFfb.act_uom,
|
|
|
+ noOfBunches: rawFfb.no_of_bunches ? Number(rawFfb.no_of_bunches) : 0,
|
|
|
+ qtyUom: rawFfb.qty_uom,
|
|
|
+ docActQty: rawFfb.doc_act_qty ? Number(rawFfb.doc_act_qty) : 0,
|
|
|
+ locArea: rawFfb.loc_area ? Number(rawFfb.loc_area) : 0,
|
|
|
+ locUom: rawFfb.loc_uom,
|
|
|
+ budgetedFfb: rawFfb.budgeted_ffb ? Number(rawFfb.budgeted_ffb) : null,
|
|
|
+ remarks: rawFfb.remarks || '',
|
|
|
+ issues: rawFfb.issues || null,
|
|
|
+ };
|
|
|
+ // Process straight through active service method to execute master enrichment and embedding pipeline
|
|
|
+ await this.ffbService.create(mappedFfb);
|
|
|
+ } catch (err) {
|
|
|
+ this.logger.error(`Error inserting FFB Production log: ${err.message}`);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ console.log('[SEED] Transaction log enrichment and embedding stream processing complete.');
|
|
|
+
|
|
|
+ return {
|
|
|
+ status: 'success',
|
|
|
+ message: 'Database seeded successfully',
|
|
|
+ };
|
|
|
+ }
|
|
|
}
|