Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
2f3b1bb
refacotr(schema): implement discussion date in disscussion table
rohxnn Aug 27, 2026
52850ca
refactor(prompt): add v2 for PII detection
rohxnn Aug 27, 2026
c07b9fc
refactor: replace Temporal CSV processing with direct Kafka productio…
rohxnn Aug 28, 2026
9b27323
fix(uploads): make Kafka delivery completion batch-scoped and preserv…
rohxnn Sep 4, 2026
c395e51
fix(uploads): atomically claim record in handle_upload to prevent dup…
rohxnn Sep 4, 2026
d672ee2
fix(prompts): update PII prompt v2 output format to specify array con…
rohxnn Sep 4, 2026
206882c
fix(ingestion): resolve event loop pool conflicts, schema validation,…
rohxnn Sep 4, 2026
97315c3
feat(uploads): record failed CSV uploads in DB and update Kafka inges…
rohxnn Sep 4, 2026
d8c4c0f
fix(pii): prevent silent content loss when LLM wraps scalar column in…
rohxnn Sep 9, 2026
c89dee4
fix(ops): stop discussion submission_date being overwritten on update…
rohxnn Sep 9, 2026
11dd3db
fix(uploads): reject invalid CSVs before touching GCS or the DB
rohxnn Sep 9, 2026
4d0ec72
add discussionDate for discussion kafka events and store in the discu…
rohxnn Sep 9, 2026
87b0130
fix(temporal): prevent PII masking silent truncation on scalar fields
rohxnn Sep 9, 2026
f52e251
test(uploads): update unit tests for inline CSV processing and auth
rohxnn Sep 9, 2026
0bf3e73
fix(uploads): set on_hold status on Kafka publish failure to prevent …
rohxnn Sep 9, 2026
f278812
fix(uploads): add startup reclaim task for stale in_progress records,…
rohxnn Sep 9, 2026
a494018
refactor(uploads): deduplicate CSV validation, remove dead code, and …
rohxnn Sep 9, 2026
65ffe82
revert back
rohxnn Sep 9, 2026
c927723
fix(uploads): prevent missing discussion date from defaulting to curr…
rohxnn Sep 9, 2026
5424d47
fix(uploads): do not fabricate placeholder fallback strings for missi…
rohxnn Sep 9, 2026
0d293c7
fix(uploads): exclude failed status rows from check_duplicate_file query
rohxnn Sep 9, 2026
10d59df
fix(uploads): add periodic background sweep loop for stale in_progres…
rohxnn Sep 9, 2026
c71366c
perf(uploads): hoist per-row schema parsing, reuse parsed DataFrame, …
rohxnn Sep 9, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,6 @@ AUTH_TOKEN=your-secret-bearer-token-here
# CSV Upload / Processing Configuration
MAX_CSV_UPLOAD_BYTES=10485760
CSV_BLOB_UPLOADS=mitra_dashboard_api_output
CSV_SCHEDULE_CRON_TIME=40 15 * * *
STORY_CSV_COLUMN=["id","Title","User name","Designation","Location","District","Organization","Report Created At","Objective","Challenges","Action Steps","Impact","Duration","Blurb","masked_blurb","Content","masked_content","Images","Pdf","Transcript Link","Session ID"]
DISCUSSION_CSV_COLUMN=["id","Title","User name","User Location","District","Participant Count","Men","Women","Children","Date of Discussion","Organization","Challenges","Solutions","Author","Language","Report Created At","Transcript Link","Image Urls","PDF Urls","Session ID"]
DISCUSSION_PARTICIPANTS_MAP={"men": "Men", "women": "Women", "children": "Children", "teacher": "Teacher", "participant count": "Participant Count"}
Expand All @@ -92,7 +91,7 @@ MAX_PDF_TEXT_CHARS=40000
# missing/null/empty a "required" path is rejected and routed to the DLQ topic
# instead of being ingested. See app/kafka/consumer.py's _validate_ingestion_schema.
STORY_KAFKA_SCHEMA={"create": {"required": ["submissionId", "submissionType", "sessionId", "tenantCode", "eventType", "eventPublishedAt", "tags.state", "tags.district", "tags.organization", "tags.programId", "tags.programName", "tags.leaderCategoryId", "tags.leaderCategoryName", "data.title", "data.designation", "data.submissionDate", "data.pdfUrls.original", "data.pdfUrls.masked", "data.transcriptLink", "data.challenges", "data.objective", "data.actionSteps", "data.impact", "data.duration", "data.blurb", "data.content"], "optional": ["data.imageUrls"]}, "update": {"required": ["submissionId", "submissionType", "sessionId", "tenantCode", "eventType", "eventPublishedAt"], "newValuesNoEmpty": true}, "delete": {"required": ["submissionId", "submissionType", "sessionId", "tenantCode", "eventType", "eventPublishedAt"]}}
DISCUSSION_KAFKA_SCHEMA={"create": {"required": ["submissionId", "submissionType", "sessionId", "tenantCode", "eventType", "eventPublishedAt", "tags.state", "tags.district", "tags.organization", "tags.programId", "tags.programName", "tags.leaderCategoryId", "tags.leaderCategoryName", "data.title", "data.designation", "data.submissionDate", "data.pdfUrls.original", "data.pdfUrls.masked", "data.transcriptLink", "data.challenges", "data.solutions", "data.participantsData"], "optional": ["data.author", "data.language", "data.imageUrls"]}, "update": {"required": ["submissionId", "submissionType", "sessionId", "tenantCode", "eventType", "eventPublishedAt"], "newValuesNoEmpty": true}, "delete": {"required": ["submissionId", "submissionType", "sessionId", "tenantCode", "eventType", "eventPublishedAt"]}}
DISCUSSION_KAFKA_SCHEMA={"create": {"required": ["submissionId", "submissionType", "sessionId", "tenantCode", "eventType", "eventPublishedAt", "tags.state", "tags.district", "tags.organization", "tags.programId", "tags.programName", "tags.leaderCategoryId", "tags.leaderCategoryName", "data.title", "data.designation", "data.submissionDate", "data.discussionDate", "data.pdfUrls.original", "data.pdfUrls.masked", "data.transcriptLink", "data.challenges", "data.solutions", "data.participantsData"], "optional": ["data.author", "data.language", "data.imageUrls"]}, "update": {"required": ["submissionId", "submissionType", "sessionId", "tenantCode", "eventType", "eventPublishedAt"], "newValuesNoEmpty": true}, "delete": {"required": ["submissionId", "submissionType", "sessionId", "tenantCode", "eventType", "eventPublishedAt"]}}

# Scoped Ingestion Pipeline Configurations (JSON strings)
# Each step optionally accepts "llm_model" / "max_tokens" / "llm_timeout_seconds" to override
Expand Down
11 changes: 8 additions & 3 deletions app/api/routes/uploads.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import logging
from fastapi import APIRouter, Depends, Form, UploadFile, File
from fastapi import APIRouter, Depends, Form, UploadFile, File, BackgroundTasks
from fastapi.security import HTTPAuthorizationCredentials

from app.api.deps import verify_auth_token
Expand All @@ -19,6 +19,7 @@

@uploads_router.post("/upload/", response_model=UploadResponse)
async def upload_report(
background_tasks: BackgroundTasks,
report_type: str = Form(...),
program_name: str = Form(...),
leader_category: str = Form(...),
Expand All @@ -30,7 +31,8 @@ async def upload_report(
Upload a CSV report file.

The file is stored in GCS and a tracking record is created with
status='pending' (validation passed) or status='on_hold' (validation failed).
status='pending'. Processing (column validation, Kafka publishing)
runs in the background.
"""
# Pure request-shape checks
report_type = validate_report_type(report_type)
Expand All @@ -47,15 +49,18 @@ async def upload_report(
tenant_code=tenant_code,
file_name=file.filename,
file_bytes=file_bytes,
background_tasks=background_tasks,
)


@uploads_router.post("/process/csv/{record_id}")
async def push_record(
record_id: int,
background_tasks: BackgroundTasks,
_token: HTTPAuthorizationCredentials = Depends(verify_auth_token),
):
"""
Manually trigger processing for a specific csv_upload record in pending status.
"""
return await upload_service.handle_push(record_id)
return await upload_service.handle_push(record_id, background_tasks)

Loading