from app.pipeline.pdf_reader import PDFReader from app.pipeline.layout_detector import LayoutDetector from app.pipeline.article_segmenter import ArticleSegmenter from app.pipeline.ocr_engine import OCREngine from app.pipeline.headline import detect_headline from app.pipeline.cropper import crop_article, crop_figures from app.pipeline.categorizer import Categorizer from app.pipeline.enricher import Enricher from app.config import settings import os class Pipeline: def __init__(self): self.layout = LayoutDetector() self.segmenter = ArticleSegmenter() self.ocr = OCREngine(settings.OCR_LANGS) self.cat = Categorizer() self.enricher = Enricher() def process(self, pdf_path, newspaper, edition, date, job_dir): reader = PDFReader(pdf_path) results = [] for page in reader.iter_pages(): h, w = page["image"].shape[:2] blocks = self.layout.detect(page["image"]) articles = self.segmenter.segment(blocks, w, h) for art in articles: text, conf = self.ocr.extract_text(page, art["bbox"], page["native_words"]) if len(text.strip()) < 80: # skip noise/ads continue headline = detect_headline(art, page, self.ocr) img_path = crop_article(page["image"], art["bbox"], job_dir) fig_paths = crop_figures(page["image"], art, job_dir) # Semantic Embedding for RAG raw_text_for_embed = headline + " " + text[:1000] embedding = self.enricher.embed(raw_text_for_embed) # Fetch few-shot examples from DB few_shot_examples = [] try: from app.db.session import SessionLocal from sqlalchemy import text as sqla_text db = SessionLocal() # Query for up to 3 verified examples using cosine distance rows = db.execute(sqla_text(""" SELECT headline, text, category, subcategory, summary, sentiment, keywords, persons, locations, organizations FROM articles WHERE human_verified = TRUE ORDER BY embedding <=> :v LIMIT 3 """), {"v": str(embedding)}).fetchall() for r in rows: ex = { "headline": r.headline, "text": r.text, "classification": { "category": r.category, "subcategory": r.subcategory, "summary": r.summary, "sentiment": r.sentiment, "keywords": r.keywords, "persons": r.persons, "locations": r.locations, "organizations": r.organizations } } few_shot_examples.append(ex) except Exception as e: print(f"RAG fetch failed: {e}") finally: if 'db' in locals(): db.close() meta = self.cat.classify(headline, text, few_shot_examples=few_shot_examples) results.append({ "date": date, "newspaper": newspaper, "edition": edition, "page": page["page_number"], "headline": headline, "category": meta.get("category", "Others"), "subcategory": meta.get("subcategory"), "text": text, "summary": meta.get("summary"), "keywords": meta.get("keywords", []), "persons": meta.get("persons", []), "locations": meta.get("locations", []), "organizations": meta.get("organizations", []), "sentiment": meta.get("sentiment"), "language": "en", "image_path": img_path, "figure_paths": fig_paths, "bounding_box": art["bbox"], "confidence": round(art["confidence"] * meta.get("confidence", 1), 3), "embedding": embedding, }) return results