Spaces:
Running
Running
| """Create a comprehensive PowerPoint presentation for RAG Capstone Project.""" | |
| from pptx import Presentation | |
| from pptx.util import Inches, Pt | |
| from pptx.enum.text import PP_ALIGN | |
| from pptx.dml.color import RGBColor | |
| from datetime import datetime | |
| def create_presentation(): | |
| """Create the RAG Capstone Project presentation.""" | |
| prs = Presentation() | |
| prs.slide_width = Inches(10) | |
| prs.slide_height = Inches(7.5) | |
| # Define color scheme | |
| DARK_BLUE = RGBColor(25, 55, 109) | |
| ACCENT_BLUE = RGBColor(0, 120, 215) | |
| LIGHT_GRAY = RGBColor(240, 240, 240) | |
| TEXT_DARK = RGBColor(33, 33, 33) | |
| def add_title_slide(title, subtitle=""): | |
| """Add a title slide.""" | |
| slide = prs.slides.add_slide(prs.slide_layouts[6]) # Blank layout | |
| background = slide.background | |
| fill = background.fill | |
| fill.solid() | |
| fill.fore_color.rgb = DARK_BLUE | |
| # Title | |
| title_box = slide.shapes.add_textbox(Inches(0.5), Inches(2.5), Inches(9), Inches(1.5)) | |
| title_frame = title_box.text_frame | |
| title_frame.word_wrap = True | |
| p = title_frame.paragraphs[0] | |
| p.text = title | |
| p.font.size = Pt(54) | |
| p.font.bold = True | |
| p.font.color.rgb = RGBColor(255, 255, 255) | |
| p.alignment = PP_ALIGN.CENTER | |
| # Subtitle | |
| if subtitle: | |
| subtitle_box = slide.shapes.add_textbox(Inches(0.5), Inches(4.2), Inches(9), Inches(1)) | |
| subtitle_frame = subtitle_box.text_frame | |
| p = subtitle_frame.paragraphs[0] | |
| p.text = subtitle | |
| p.font.size = Pt(28) | |
| p.font.color.rgb = ACCENT_BLUE | |
| p.alignment = PP_ALIGN.CENTER | |
| return slide | |
| def add_content_slide(title, content_items): | |
| """Add a content slide with bullet points.""" | |
| slide = prs.slides.add_slide(prs.slide_layouts[6]) | |
| background = slide.background | |
| fill = background.fill | |
| fill.solid() | |
| fill.fore_color.rgb = RGBColor(255, 255, 255) | |
| # Title bar | |
| title_shape = slide.shapes.add_shape(1, Inches(0), Inches(0), Inches(10), Inches(0.8)) | |
| title_shape.fill.solid() | |
| title_shape.fill.fore_color.rgb = DARK_BLUE | |
| title_shape.line.color.rgb = DARK_BLUE | |
| # Title text | |
| title_frame = title_shape.text_frame | |
| p = title_frame.paragraphs[0] | |
| p.text = title | |
| p.font.size = Pt(40) | |
| p.font.bold = True | |
| p.font.color.rgb = RGBColor(255, 255, 255) | |
| p.space_before = Pt(8) | |
| p.space_after = Pt(8) | |
| # Content | |
| text_box = slide.shapes.add_textbox(Inches(0.7), Inches(1.2), Inches(8.6), Inches(6)) | |
| text_frame = text_box.text_frame | |
| text_frame.word_wrap = True | |
| for i, item in enumerate(content_items): | |
| if i > 0: | |
| p = text_frame.add_paragraph() | |
| else: | |
| p = text_frame.paragraphs[0] | |
| p.text = item | |
| p.level = 0 | |
| p.font.size = Pt(18) | |
| p.font.color.rgb = TEXT_DARK | |
| p.space_before = Pt(6) | |
| p.space_after = Pt(6) | |
| return slide | |
| def add_two_column_slide(title, left_title, left_items, right_title, right_items): | |
| """Add a two-column content slide.""" | |
| slide = prs.slides.add_slide(prs.slide_layouts[6]) | |
| background = slide.background | |
| fill = background.fill | |
| fill.solid() | |
| fill.fore_color.rgb = RGBColor(255, 255, 255) | |
| # Title bar | |
| title_shape = slide.shapes.add_shape(1, Inches(0), Inches(0), Inches(10), Inches(0.8)) | |
| title_shape.fill.solid() | |
| title_shape.fill.fore_color.rgb = DARK_BLUE | |
| title_shape.line.color.rgb = DARK_BLUE | |
| title_frame = title_shape.text_frame | |
| p = title_frame.paragraphs[0] | |
| p.text = title | |
| p.font.size = Pt(40) | |
| p.font.bold = True | |
| p.font.color.rgb = RGBColor(255, 255, 255) | |
| p.space_before = Pt(8) | |
| p.space_after = Pt(8) | |
| # Left column | |
| left_box = slide.shapes.add_textbox(Inches(0.4), Inches(1.2), Inches(4.6), Inches(6)) | |
| left_frame = left_box.text_frame | |
| left_frame.word_wrap = True | |
| p = left_frame.paragraphs[0] | |
| p.text = left_title | |
| p.font.size = Pt(20) | |
| p.font.bold = True | |
| p.font.color.rgb = ACCENT_BLUE | |
| p.space_after = Pt(8) | |
| for item in left_items: | |
| p = left_frame.add_paragraph() | |
| p.text = item | |
| p.level = 0 | |
| p.font.size = Pt(15) | |
| p.font.color.rgb = TEXT_DARK | |
| p.space_after = Pt(6) | |
| # Right column | |
| right_box = slide.shapes.add_textbox(Inches(5.0), Inches(1.2), Inches(4.6), Inches(6)) | |
| right_frame = right_box.text_frame | |
| right_frame.word_wrap = True | |
| p = right_frame.paragraphs[0] | |
| p.text = right_title | |
| p.font.size = Pt(20) | |
| p.font.bold = True | |
| p.font.color.rgb = ACCENT_BLUE | |
| p.space_after = Pt(8) | |
| for item in right_items: | |
| p = right_frame.add_paragraph() | |
| p.text = item | |
| p.level = 0 | |
| p.font.size = Pt(15) | |
| p.font.color.rgb = TEXT_DARK | |
| p.space_after = Pt(6) | |
| return slide | |
| # Slide 1: Title Slide | |
| add_title_slide( | |
| "RAG Capstone Project", | |
| "Retrieval-Augmented Generation Pipeline with Advanced Evaluation" | |
| ) | |
| # Slide 2: Project Overview | |
| add_content_slide( | |
| "Project Overview", | |
| [ | |
| "π― Goal: Build a production-ready RAG system with comprehensive evaluation", | |
| "", | |
| "π Key Components:", | |
| " β’ Document ingestion from RAGBench datasets (15+ datasets)", | |
| " β’ Flexible chunking strategies (6 different approaches)", | |
| " β’ Multiple embedding models (8 different embeddings)", | |
| " β’ Advanced LLM-based evaluation framework", | |
| " β’ Real-time monitoring and audit trails", | |
| "", | |
| "π§ Tech Stack: Python, Streamlit, ChromaDB, Groq LLM API, Sentence Transformers" | |
| ] | |
| ) | |
| # Slide 3: RAG Pipeline Architecture | |
| add_content_slide( | |
| "RAG Pipeline Architecture", | |
| [ | |
| "1οΈβ£ DATA INGESTION", | |
| " Load documents from 15+ RAGBench datasets (CovidQA, CUAD, FinQA, etc.)", | |
| "", | |
| "2οΈβ£ DOCUMENT CHUNKING", | |
| " Apply 6 chunking strategies to split documents into manageable pieces", | |
| "", | |
| "3οΈβ£ EMBEDDING & VECTORIZATION", | |
| " Convert chunks to dense vectors using multiple embedding models", | |
| "", | |
| "4οΈβ£ VECTOR STORAGE", | |
| " Store in ChromaDB with semantic search capabilities", | |
| "", | |
| "5οΈβ£ RETRIEVAL & RANKING", | |
| " Retrieve relevant documents based on query similarity", | |
| "", | |
| "6οΈβ£ RESPONSE GENERATION", | |
| " Use Groq LLM to generate answers grounded in retrieved documents" | |
| ] | |
| ) | |
| # Slide 4: Chunking Strategies | |
| add_two_column_slide( | |
| "Document Chunking Strategies", | |
| "Chunking Methods", | |
| [ | |
| "1. Dense Chunking", | |
| " Fixed-size chunks (512 tokens) with overlap", | |
| " Best for: Uniform content", | |
| "", | |
| "2. Sparse Chunking", | |
| " Semantic boundaries (paragraphs)", | |
| " Best for: Structured documents", | |
| "", | |
| "3. Hybrid Chunking", | |
| " Combines dense + semantic splitting", | |
| " Best for: Mixed content types", | |
| ], | |
| "Advanced Methods", | |
| [ | |
| "4. Re-ranking Chunking", | |
| " Chunks with relevance re-ranking", | |
| " Best for: High precision retrieval", | |
| "", | |
| "5. Row-based Chunking", | |
| " Preserves data structure for tables", | |
| " Best for: Tabular data", | |
| "", | |
| "6. Entity-based Chunking", | |
| " Groups by semantic entities", | |
| " Best for: Knowledge extraction", | |
| ] | |
| ) | |
| # Slide 5: Embedding Models | |
| add_content_slide( | |
| "Embedding Models Used", | |
| [ | |
| "πΉ General Purpose Models:", | |
| " β’ sentence-transformers/all-mpnet-base-v2 (High quality, 768-dim)", | |
| " β’ sentence-transformers/all-MiniLM-L6-v2 (Fast, lightweight, 384-dim)", | |
| "", | |
| "πΉ Domain-Specific Models:", | |
| " β’ emilyalsentzer/Bio_ClinicalBERT (Clinical text, 768-dim)", | |
| " β’ microsoft/BiomedNLP-PubMedBERT (Medical abstracts, 768-dim)", | |
| " β’ allenai/specter (Academic papers, 768-dim)", | |
| "", | |
| "πΉ Multilingual Models:", | |
| " β’ sentence-transformers/multilingual-MiniLM-L12-v2 (110 languages)", | |
| " β’ sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2", | |
| "", | |
| "πΉ API-Based Model:", | |
| " β’ gemini-embedding-001 (Google Gemini API embeddings)" | |
| ] | |
| ) | |
| # Slide 6: RAG Evaluation Challenge | |
| add_content_slide( | |
| "The RAG Evaluation Challenge", | |
| [ | |
| "β Why Traditional Metrics Fail?", | |
| " β’ BLEU/ROUGE only measure surface-level similarity", | |
| " β’ Don't evaluate grounding in retrieved documents", | |
| " β’ Can't detect hallucinations or factual errors", | |
| "", | |
| "β What We Need?", | |
| " β’ Metrics that measure document relevance to query", | |
| " β’ Metrics that measure document usage in response", | |
| " β’ Metrics that evaluate response grounding (no hallucinations)", | |
| " β’ Metrics that assess completeness of coverage", | |
| "", | |
| "π Our Solution: LLM-based Evaluation Framework", | |
| " Inspired by RAGBench paper (arXiv:2407.11005)" | |
| ] | |
| ) | |
| # Slide 7: TRACE Framework | |
| add_content_slide( | |
| "TRACE Framework - 4 Core Metrics", | |
| [ | |
| "π΄ RELEVANCE (R)", | |
| " Fraction of retrieved context relevant to the query", | |
| " Formula: Ξ£ Len(Relevant spans) / Ξ£ Len(All retrieved docs)", | |
| "", | |
| "π΅ UTILIZATION (T)", | |
| " Fraction of retrieved context used in the response", | |
| " Formula: Ξ£ Len(Used spans) / Ξ£ Len(All retrieved docs)", | |
| "", | |
| "π’ ADHERENCE (A)", | |
| " Boolean: Is the response fully grounded in documents?", | |
| " Detects hallucinations and unsupported claims", | |
| "", | |
| "π‘ COMPLETENESS (C)", | |
| " Fraction of relevant information covered by response", | |
| " Formula: Len(Relevant β© Used) / Len(Relevant)" | |
| ] | |
| ) | |
| # Slide 8: LLM-Based Evaluation | |
| add_content_slide( | |
| "Advanced LLM-Based Evaluation", | |
| [ | |
| "π€ GPT Labeling Approach:", | |
| " β’ Use LLM (GPT-4/Groq) to annotate response sentences", | |
| " β’ Match each response sentence to supporting document spans", | |
| " β’ Detect fully supported, partially supported, and unsupported sentences", | |
| "", | |
| "π Evaluation Process:", | |
| " 1. Extract all sentences from both response and documents", | |
| " 2. Prompt LLM to identify relevant document sentences for query", | |
| " 3. Prompt LLM to map response sentences to document spans", | |
| " 4. Calculate support metrics at sentence and document level", | |
| "", | |
| "β¨ Advantages:", | |
| " β Semantic understanding (not just keyword matching)", | |
| " β Detects hallucinations and contradictions", | |
| " β Provides explainable audit trails", | |
| " β Works across different domains and languages" | |
| ] | |
| ) | |
| # Slide 9: Evaluation Output Metrics | |
| add_two_column_slide( | |
| "Evaluation Output & Metrics", | |
| "Per-Response Metrics", | |
| [ | |
| "β Context Relevance (0-1)", | |
| " How much retrieved content is relevant?", | |
| "", | |
| "β Context Utilization (0-1)", | |
| " How much retrieved content was used?", | |
| "", | |
| "β Adherence (0-1)", | |
| " Is response grounded in documents?", | |
| "", | |
| "β Completeness (0-1)", | |
| " Does response cover relevant information?", | |
| ], | |
| "Aggregate Metrics", | |
| [ | |
| "π RMSE Metrics", | |
| " Root Mean Squared Error for each metric", | |
| "", | |
| "π AUC-ROC Metrics", | |
| " Area Under ROC Curve for binary classification", | |
| "", | |
| "π― Average Score", | |
| " Mean of all 4 TRACE metrics", | |
| "", | |
| "π Detailed Audit Trail", | |
| " Sentence-level support information", | |
| ] | |
| ) | |
| # Slide 10: Audit Trail & Explainability | |
| add_content_slide( | |
| "Explainability & Audit Trails", | |
| [ | |
| "π Detailed Audit Information Captured:", | |
| "", | |
| "β Original Query", | |
| " User's question or request", | |
| "", | |
| "β LLM Prompt", | |
| " Exact instructions sent to LLM for evaluation", | |
| "", | |
| "β LLM Response", | |
| " Complete evaluation reasoning from LLM", | |
| "", | |
| "β Retrieved Documents", | |
| " Context provided to the RAG system", | |
| "", | |
| "β Sentence-Level Support Map", | |
| " Which document spans support each response sentence", | |
| "", | |
| "π― Enables: Root cause analysis, model improvements, and trust building" | |
| ] | |
| ) | |
| # Slide 11: System Architecture | |
| add_content_slide( | |
| "System Architecture Overview", | |
| [ | |
| "π± Frontend: Streamlit Web Interface", | |
| " β’ Interactive configuration panel", | |
| " β’ Real-time collection management", | |
| " β’ Chat interface with context display", | |
| " β’ Evaluation results visualization", | |
| "", | |
| "βοΈ Backend: Python Services", | |
| " β’ Vector store management (ChromaDB with SQLite indexing)", | |
| " β’ Embedding pipeline with 8 models", | |
| " β’ LLM integration (Groq API with rate limiting)", | |
| " β’ Advanced evaluation engine", | |
| "", | |
| "π Data Layer: ChromaDB", | |
| " β’ Persistent vector storage", | |
| " β’ SQLite metadata indexing", | |
| " β’ Multi-collection support", | |
| " β’ 4 active collections from RAGBench" | |
| ] | |
| ) | |
| # Slide 12: Key Features | |
| add_two_column_slide( | |
| "Key System Features", | |
| "Data Management", | |
| [ | |
| "β 15+ RAGBench datasets", | |
| "β Flexible chunking strategies", | |
| "β Multiple embedding models", | |
| "β Real-time collection loading", | |
| "β Batch processing capability", | |
| "β Persistent storage (ChromaDB)", | |
| "β SQLite metadata indexing", | |
| ], | |
| "Evaluation & Monitoring", | |
| [ | |
| "β LLM-based evaluation", | |
| "β 4 TRACE metrics", | |
| "β RMSE & AUC metrics", | |
| "β Sentence-level analysis", | |
| "β Hallucination detection", | |
| "β Detailed audit trails", | |
| "β JSON export & visualization", | |
| ] | |
| ) | |
| # Slide 13: LLM Configuration | |
| add_content_slide( | |
| "LLM Configuration & Settings", | |
| [ | |
| "π§ Groq LLM Models Supported:", | |
| " β’ meta-llama/llama-4-maverick-17b-128e-instruct", | |
| " β’ llama-3.1-8b-instant", | |
| " β’ openai/gpt-oss-120b", | |
| "", | |
| "βοΈ Configurable Parameters:", | |
| " β’ Temperature: 0.0 (deterministic for evaluation)", | |
| " β’ Max Tokens: 2048 (sufficient for detailed analysis)", | |
| " β’ Rate Limit: 30 RPM (Groq API limit)", | |
| " β’ Rate Limit Delay: 2.0 seconds (throttling)", | |
| "", | |
| "π― System Prompt:", | |
| " Specialized fact-checking and citation verification prompt", | |
| " Enables LLM to evaluate without additional fine-tuning" | |
| ] | |
| ) | |
| # Slide 14: Data Flow Example | |
| add_content_slide( | |
| "Data Flow Example: A Question in RAG", | |
| [ | |
| "1οΈβ£ USER QUERY", | |
| ' "What are the COVID-19 vaccine side effects?"', | |
| "", | |
| "2οΈβ£ RETRIEVAL", | |
| " ChromaDB retrieves top 5 similar chunks from CovidQA dataset", | |
| "", | |
| "3οΈβ£ CONTEXT PREPARATION", | |
| " Relevant medical documents selected and formatted", | |
| "", | |
| "4οΈβ£ RESPONSE GENERATION", | |
| " Groq LLM generates answer: 'Common side effects include...'", | |
| "", | |
| "5οΈβ£ EVALUATION", | |
| " β’ LLM verifies: Are claims supported by documents?", | |
| " β’ Calculates: Relevance=0.92, Utilization=0.87, Adherence=1.0, Completeness=0.95", | |
| "", | |
| "6οΈβ£ OUTPUT", | |
| " JSON with metrics, audit trail, and source documents" | |
| ] | |
| ) | |
| # Slide 15: Use Cases | |
| add_content_slide( | |
| "Real-World Use Cases", | |
| [ | |
| "π Document Q&A Systems", | |
| " Help desk, knowledge base search, document retrieval", | |
| "", | |
| "π₯ Medical Information Retrieval", | |
| " Clinical decision support, patient education", | |
| "", | |
| "βοΈ Legal Document Analysis", | |
| " Contract review, case law research, compliance checking", | |
| "", | |
| "π° Financial Analysis", | |
| " SEC filing analysis, market research, investment insights", | |
| "", | |
| "π Academic Research", | |
| " Paper indexing, literature review, citation analysis", | |
| "", | |
| "π’ Enterprise Knowledge Management", | |
| " Internal document search, policy retrieval, FAQs" | |
| ] | |
| ) | |
| # Slide 16: Performance & Results | |
| add_content_slide( | |
| "System Performance & Achievements", | |
| [ | |
| "β Successfully Processed:", | |
| " β’ 4 collections from RAGBench datasets", | |
| " β’ Recovered and re-indexed 4M+ vector embeddings in ChromaDB", | |
| " β’ 8 different embedding models tested", | |
| " β’ 6 chunking strategies implemented and evaluated", | |
| "", | |
| "π Evaluation Coverage:", | |
| " β’ Batch evaluation of 100+ test cases", | |
| " β’ Per-sentence analysis with GPT labeling", | |
| " β’ Comprehensive audit trails with LLM reasoning", | |
| "", | |
| "β‘ Performance Metrics:", | |
| " β’ Sub-second retrieval latency", | |
| " β’ Batch evaluation: ~2-3 seconds per query (with GPT labeling)", | |
| " β’ Rate limiting: Controlled via Groq API settings" | |
| ] | |
| ) | |
| # Slide 17: Technical Innovations | |
| add_content_slide( | |
| "Technical Innovations", | |
| [ | |
| "πΉ Advanced ChromaDB Recovery", | |
| " Smart SQLite index rebuilding preserving all vector data", | |
| "", | |
| "πΉ Smart Collection Naming", | |
| " Automatic metadata extraction with interactive fallback UI", | |
| "", | |
| "πΉ Sentence-Level Evaluation", | |
| " Maps individual response sentences to document spans", | |
| "", | |
| "πΉ Multi-Metric Evaluation", | |
| " RMSE and AUC-ROC metrics alongside TRACE framework", | |
| "", | |
| "πΉ Explainable AI", | |
| " Complete audit trails showing LLM reasoning for each decision", | |
| "", | |
| "πΉ Flexible Pipeline", | |
| " Modular design allows easy swapping of chunking, embedding, and LLM components" | |
| ] | |
| ) | |
| # Slide 18: Challenges & Solutions | |
| add_two_column_slide( | |
| "Challenges & Solutions", | |
| "Challenges Faced", | |
| [ | |
| "π΄ ChromaDB Index Corruption", | |
| " Collection folders orphaned from SQLite", | |
| "", | |
| "π΄ Evaluation Consistency", | |
| " Different chunking strategies vary in effectiveness", | |
| "", | |
| "π΄ Rate Limiting", | |
| " Groq API has strict RPM limits", | |
| "", | |
| "π΄ Hallucination Detection", | |
| " Hard to detect factual errors without reference", | |
| "", | |
| "π΄ Scalability", | |
| " Large batch evaluations take time", | |
| ], | |
| "Solutions Implemented", | |
| [ | |
| "β Data-Preserving Recovery", | |
| " Direct SQLite rebuild scripts", | |
| "", | |
| "β Comprehensive Testing", | |
| " Baseline metrics for different strategies", | |
| "", | |
| "β Intelligent Queuing", | |
| " Configurable rate limit delays", | |
| "", | |
| "β LLM Verification", | |
| " Adherence metric detects unsupported claims", | |
| "", | |
| "β Batch Processing", | |
| " Parallel processing where possible", | |
| ] | |
| ) | |
| # Slide 19: Future Roadmap | |
| add_content_slide( | |
| "Future Development Roadmap", | |
| [ | |
| "π Phase 2: Production Enhancements", | |
| " β’ Distributed processing for large-scale evaluation", | |
| " β’ Caching layer for frequently accessed documents", | |
| " β’ Real-time monitoring dashboard", | |
| "", | |
| "π Phase 3: Advanced Features", | |
| " β’ Multimodal RAG (images, tables, PDFs)", | |
| " β’ Knowledge graph integration", | |
| " β’ Cross-domain transfer learning", | |
| "", | |
| "π Phase 4: Enterprise Features", | |
| " β’ Multi-tenant support", | |
| " β’ Fine-tuned models for specific domains", | |
| " β’ Advanced security and compliance", | |
| "", | |
| "π Phase 5: Research Contributions", | |
| " β’ Publication of benchmark results", | |
| " β’ Open-source evaluation framework", | |
| " β’ Industry collaboration" | |
| ] | |
| ) | |
| # Slide 20: Conclusion | |
| add_title_slide( | |
| "Key Takeaways", | |
| "Advanced RAG with Comprehensive Evaluation" | |
| ) | |
| # Add content to conclusion | |
| slide = prs.slides[-1] | |
| text_box = slide.shapes.add_textbox(Inches(1), Inches(2.5), Inches(8), Inches(4)) | |
| text_frame = text_box.text_frame | |
| points = [ | |
| "β Complete RAG pipeline from ingestion to evaluation", | |
| "β Flexible architecture supporting multiple chunking and embedding strategies", | |
| "β LLM-based evaluation with sentence-level grounding verification", | |
| "β Explainable AI with comprehensive audit trails", | |
| "β Production-ready implementation with real data (RAGBench datasets)", | |
| "β Addresses critical RAG evaluation challenges", | |
| ] | |
| for i, point in enumerate(points): | |
| if i == 0: | |
| p = text_frame.paragraphs[0] | |
| else: | |
| p = text_frame.add_paragraph() | |
| p.text = point | |
| p.font.size = Pt(20) | |
| p.font.color.rgb = TEXT_DARK | |
| p.space_before = Pt(12) | |
| p.space_after = Pt(12) | |
| # Save presentation | |
| output_file = "RAG_Capstone_Project_Presentation.pptx" | |
| prs.save(output_file) | |
| print(f"β Presentation created successfully: {output_file}") | |
| print(f"π Total slides: {len(prs.slides)}") | |
| print(f"πΎ File size: {len(open(output_file, 'rb').read()) / 1024:.2f} KB") | |
| if __name__ == "__main__": | |
| create_presentation() | |