| Metadata | Value |
|---|---|
| Status | Completed |
| Version | 1.3.1 |
| Last Updated | 2026-09-05 |
| Author | Sangeetha Grantha Team |
2026-07-19 — completed. The re-import held below has since run. Verified against the dev DB:
Check Result Krithis imported 1,226 of the 1,245 target (98.5%) — Tyagaraja 675, Dikshitar 481, Syama Sastri 70 Krithis with canonical sections 1,225 of 1,226 Krithis with a raga link 1,226 (zero unresolved) krithi_revisions1,292 rows across 1,225 krithis (versioned canon populated from row one) krithi_section_revisions15,651 rows parsed_payloadformat1,238 of 1,238 canonical — zero legacy ScrapedKrithiMetadataThe last row is TRACK-096’s explicit unblock condition; that track is now clear to run its deletion cleanup. Residual data quality was tracked separately: 29 krithis (2.4%) with section-count mismatches → TRACK-133 (closed 2026-09-02, 108 → 0 rows; durable pallavi-echo parser 2026-09-05 — implementation); 16 duplicate raga pairs created by an import-side normalisation gap → TRACK-132.
Import 1,245 krithis for the Carnatic Trinity composers via the bulk import UI:
Source CSVs are in database/for_import/. Each CSV has columns: Krithi, Raga, Hyperlink.
39__seed_malavasri_raga.sql (Mālāvashree)40__seed_missing_trinity_ragas.sql (9 base ragas)
Three separate batches via http://localhost:5001/bulk-import:
Kotlin-side HTML scraping in ScrapeWorker produced lyrics with:
ScrapeWorker now passes only CSV metadata (rawTitle, rawRaga) and leaves rawLyrics/rawPayload null. This triggers ImportService.shouldEnqueueHtmlExtraction() → extraction_queue → Python worker.
modules/backend/api/.../bulkimport/workers/ScrapeWorker.kt — removed Kotlin scraping, delegate to Pythontools/krithi-extract-enrich-worker/src/structure_parser.py — added Devanagari pronunciation guide boilerplate detectionCSV Upload → ScrapeWorker (CSV metadata only)
→ ImportService.submitImports() (no rawLyrics/rawPayload)
→ shouldEnqueueHtmlExtraction() = true
→ extraction_queue table
→ Python extraction worker
→ HtmlTextExtractor (fetch + parse HTML)
→ StructureParser._find_metadata_boundaries() (truncate at Word Division)
→ StructureParser._extract_sections() (first language only)
→ StructureParser._is_boilerplate() (filter pronunciation guides)
ImportService.shouldEnqueueHtmlExtraction() (line ~117-122 of ImportService.kt) returns true when:
rawPayload == null AND rawLyrics.isNullOrBlank() AND source format is HTMLThe extraction worker handles transliteration variations automatically:
normalizer.py:normalize_for_matching())Kalyāni → KalyaniKalyaani → KalyaniThodi → TodiBrindāvana Sāranga → BrindavanaSarangaidentity_candidates.py)All transliteration variants now resolve correctly:
Kalyani, Kalyāni, Kalyaani → kalyani ✓
Todi, Thodi, Tōdi → todi ✓
Gaula, Gowla → both found ✓
Bauli, Bowli → both found ✓
Brindāvana Sāranga → brindavanasaranga ✓
make test)webScrapingService/rateLimiter from ScrapeWorker constructordatabase/for_import/*.csv — cleaneddatabase/migrations/39__seed_malavasri_raga.sql — Mālāvashree ragadatabase/migrations/40__seed_missing_trinity_ragas.sql — 9 base ragas (v1.2.0)database/migrations/41__unique_import_source_name.sql — Fixed concurrent import source creationmodules/backend/api/.../bulkimport/workers/ScrapeWorker.kt — delegate to Pythontools/krithi-extract-enrich-worker/src/structure_parser.py — boilerplate detectionconductor/tracks.md — updated