Download rag_engine.py from zaheer140/RagAgent: direct link, hf CLI and curl.
- Browser
- Download file 5.81 kB
-
https://huggingface.co/spaces/zaheer140/RagAgent/resolve/main/rag_engine.py
- Command line
-
hf download hf://spaces/zaheer140/RagAgent/rag_engine.py
-
curl -L -o rag_engine.py https://huggingface.co/spaces/zaheer140/RagAgent/resolve/main/rag_engine.py
5.81 kB
| from typing import List, Dict, Any | |
| from rag.ocr import extract_text as ocr_extract_text | |
| from rag.chunker import chunk_text as chunker_chunk_text | |
| from rag.retriever import get_pinecone_store as retriever_get_pinecone_store, retrieve_hybrid | |
| from rag.reranker import rerank | |
| from rag.engine import agent_stream as engine_agent_stream | |
| # Re-expose the system prompt for any direct imports (though now managed in rag/prompt.py) | |
| from rag.prompt import SYSTEM_PROMPT | |
| def extract_text(file_bytes: bytes) -> List[Dict[str, Any]]: | |
| """ | |
| Extracts text from PDF pages (Proxy to rag/ocr.py). | |
| """ | |
| return ocr_extract_text(file_bytes) | |
| def chunk_text(pages: List[Dict[str, Any]], filename: str) -> List[Dict[str, Any]]: | |
| """ | |
| Splits pages into recursive/semantic chunks (Proxy to rag/chunker.py). | |
| """ | |
| return chunker_chunk_text(pages, filename) | |
| def save_to_pinecone(machine_id: str, chunks: List[Dict[str, Any]]): | |
| """ | |
| Processes raw chunks (classification, metadata generation, sequential linking) | |
| and saves them to both Pinecone and the local cache (Proxy to rag/ingestion.py logic). | |
| """ | |
| if not chunks: | |
| return | |
| filename = chunks[0]["filename"] | |
| # Use first chunk text as sample for classification | |
| sample_text = chunks[0]["text"] if chunks else "" | |
| from rag.classifier import classify_document | |
| from rag.metadata import generate_metadata | |
| from langchain_core.documents import Document | |
| from config import STORE_DIR | |
| import json | |
| # 1. Automatically classify document type | |
| doc_type = classify_document(filename, sample_text) | |
| print(f"RAG Proxy: Classified '{filename}' as '{doc_type}'") | |
| # 2. Generate heading detection and sequential links | |
| enriched_chunks = generate_metadata(chunks, machine_id, doc_type) | |
| # 3. Upload to Pinecone | |
| try: | |
| vector_store = retriever_get_pinecone_store(machine_id) | |
| documents = [ | |
| Document( | |
| page_content=c["text"], | |
| metadata={ | |
| "filename": c["filename"], | |
| "page": c["page"], | |
| "chunk_id": c["chunk_id"], | |
| "document_type": c["document_type"], | |
| "section": c["section"], | |
| "heading": c["heading"], | |
| "section_number": c.get("section_number", ""), | |
| "previous_chunk": c["previous_chunk"] or "", | |
| "next_chunk": c["next_chunk"] or "", | |
| "machine_id": machine_id | |
| } | |
| ) | |
| for c in enriched_chunks | |
| ] | |
| vector_store.add_documents(documents) | |
| print(f"RAG Proxy: Successfully uploaded {len(documents)} chunks to Pinecone.") | |
| except Exception as e: | |
| print(f"RAG Proxy: Failed to upload to Pinecone: {e}") | |
| # 4. Save to local chunks cache (for BM25 indexing & context expansion) | |
| from rag.retriever import load_local_chunks, clear_bm25_cache | |
| local_chunks = load_local_chunks(machine_id) | |
| # Remove existing chunks for this file if we are re-uploading | |
| local_chunks = [c for c in local_chunks if c["filename"] != filename] | |
| local_chunks.extend(enriched_chunks) | |
| cache_dir = STORE_DIR / machine_id | |
| cache_dir.mkdir(parents=True, exist_ok=True) | |
| cache_path = cache_dir / "chunks_cache.json" | |
| with open(cache_path, "w", encoding="utf-8") as f: | |
| json.dump(local_chunks, f, indent=2, ensure_ascii=False) | |
| try: | |
| from database import save_chunks_to_db | |
| save_chunks_to_db(machine_id, enriched_chunks) | |
| except Exception as e: | |
| print(f"RAG Proxy: Failed to save chunks to PostgreSQL: {e}", flush=True) | |
| # 5. Clear the BM25 cache for this machine to force rebuild on next query | |
| clear_bm25_cache(machine_id) | |
| # 6. Invalidate cached chat answers for this machine — a cached "not found" or a | |
| # cached answer built from the old chunk set must not outlive this new upload. | |
| from rag.engine import clear_query_cache | |
| clear_query_cache(machine_id) | |
| def get_pinecone_store(machine_id: str): | |
| """ | |
| Retrieves the Pinecone Vector Store for the machine namespace. | |
| """ | |
| return retriever_get_pinecone_store(machine_id) | |
| def retrieve(query: str, machine_id: str) -> List[Dict[str, Any]]: | |
| """ | |
| Retrieves, reranks, and expands adjacent context in correct reading order. | |
| Used by the AI task and alert extraction endpoints in main.py. | |
| """ | |
| from rag.classifier import classify_question | |
| from rag.query_expander import expand_query | |
| from rag.retriever import expand_context | |
| # 1. Classify query intent | |
| intent = classify_question(query) | |
| # 2. Expand queries | |
| queries = expand_query(query) | |
| # 3. Perform hybrid retrieval | |
| merged = retrieve_hybrid(queries, machine_id, intent) | |
| if not merged: | |
| return [] | |
| # 4. Rerank to top 12 (increased recall to capture entire tables) | |
| top_reranked = rerank(query, merged, top_n=12) | |
| # 5. Run context expansion to pull adjacent table parts and sort them in correct page order | |
| expanded = expand_context(top_reranked, machine_id) | |
| # 6. Map back to the exact format main.py expects (in correct reading sequence) | |
| results = [] | |
| for idx, c in enumerate(expanded): | |
| results.append({ | |
| "id": idx, | |
| "text": c["text"], | |
| "filename": c["filename"], | |
| "score": c.get("score", 0.0), | |
| "page": c["page"] | |
| }) | |
| return results | |
| async def agent_stream(message: str, machine_id: str, history: List[Dict[str, Any]]): | |
| """ | |
| Streams RAG v2 responses using SSE (Proxy to rag/engine.py). | |
| """ | |
| async for event in engine_agent_stream(message, machine_id, history): | |
| yield event | |