Sangeetha-Grantha

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_revisions 1,292 rows across 1,225 krithis (versioned canon populated from row one)
krithi_section_revisions 15,651 rows
parsed_payload format 1,238 of 1,238 canonical — zero legacy ScrapedKrithiMetadata

The 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 mismatchesTRACK-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.

2026-07-11 — held by decision (superseded) > The prerequisites for a *clean* re-import are now in place: > the versioned-canon schema + write path (TRACK-117), the auto-approval revision attribution > (TRACK-117 — approvals now record provenance from the extraction), and the structural-voting > migration off the legacy scraper DTO (TRACK-096). The re-import itself (`make db-reset` → three > bulk-import batches, ~1,245 krithis re-scraped from guru-guha.blogspot.com over hours) was > **deliberately deferred** to a supervised session — it drops the dev DB and is a large > outward-facing scrape. When it runs, it will populate `krithi_revisions` + per-section provenance > from row one, and unblock TRACK-096's final cleanup (deleting `ScrapedKrithiMetadata` + the > dual-format fallback once no legacy payloads remain).

Goal

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.

Pre-Import Steps

CSV Cleanup

Raga Gap Seeding (Migrations 39-40)

Import Strategy

Three separate batches via http://localhost:5001/bulk-import:

  1. Syama Sastri (smallest, validates flow)
  2. Dikshitar
  3. Thyagaraja

Scraping Pipeline Fix (v1.1.0 — 2026-03-12)

Problem

Kotlin-side HTML scraping in ScrapeWorker produced lyrics with:

Solution: Delegate to Python Extraction Worker

ScrapeWorker now passes only CSV metadata (rawTitle, rawRaga) and leaves rawLyrics/rawPayload null. This triggers ImportService.shouldEnqueueHtmlExtraction()extraction_queue → Python worker.

Files Changed

Pipeline Flow (After Fix)

CSV 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)

Key Mechanism

ImportService.shouldEnqueueHtmlExtraction() (line ~117-122 of ImportService.kt) returns true when:

Post-Import

Raga Transliteration Handling (v1.2.0 — 2026-03-13)

How It Works

The extraction worker handles transliteration variations automatically:

Normalization Pipeline (normalizer.py:normalize_for_matching())

Identity Discovery (identity_candidates.py)

Test Results

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 ✓

Benefits

Remaining Steps

  1. Restart backend to pick up Kotlin changes
  2. Delete old Syama Sastri and Thyagaraja import batches from DB
  3. Re-upload both CSVs (now flows through Python extraction)
  4. Verify extracted lyrics are clean (no Word Division, no pronunciation guides)
  5. Run backend tests (make test)
  6. Optional cleanup: remove unused webScrapingService/rateLimiter from ScrapeWorker constructor

Files Modified