Spaces:
Runtime error
Runtime error
Julien Simon Claude Opus 4.5 commited on
Commit Β·
ed005f8
1
Parent(s): 1521cd2
refactor: Reorganize PDFs and improve error handling
Browse files- Move arXiv research papers to pdf_research/ directory
- Add IEA energy reports and publications to pdf_energy/
- Update README to reflect new document content (clean energy, renewables, EVs, CCUS)
- Create pdf symlink for default document source
- Improve security by hiding internal error details from users in stream output
- Replace print statements with proper logger.warning/error calls
- Remove TEST_REVIEW.md and .DS_Store files
- Add consistent trailing newlines to source files
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- .coveragerc +2 -0
- .gitignore +2 -0
- README.md +9 -14
- models.py +2 -0
- qa_chain.py +4 -3
- tests/TEST_REVIEW.md +0 -370
- tests/__init__.py +2 -0
- tests/conftest.py +2 -0
- tests/test_cli.py +2 -0
- tests/test_config.py +2 -0
- tests/test_models.py +2 -0
- tests/test_qa_chain.py +1 -1
- tests/test_qa_chain_final.py +2 -0
- tests/test_retrievers.py +2 -0
- tests/test_retrievers_edge_cases.py +2 -0
- tests/test_utils.py +2 -0
- tests/test_utils_edge_cases.py +2 -0
- tests/test_vectorstore.py +2 -0
- utils.py +2 -0
.coveragerc
CHANGED
|
@@ -21,3 +21,5 @@ exclude_lines =
|
|
| 21 |
if TYPE_CHECKING:
|
| 22 |
@abstractmethod
|
| 23 |
|
|
|
|
|
|
|
|
|
| 21 |
if TYPE_CHECKING:
|
| 22 |
@abstractmethod
|
| 23 |
|
| 24 |
+
|
| 25 |
+
|
.gitignore
CHANGED
|
@@ -35,3 +35,5 @@ Thumbs.db
|
|
| 35 |
vectorstore/
|
| 36 |
*.log
|
| 37 |
|
|
|
|
|
|
|
|
|
| 35 |
vectorstore/
|
| 36 |
*.log
|
| 37 |
|
| 38 |
+
|
| 39 |
+
|
README.md
CHANGED
|
@@ -34,20 +34,15 @@ This application provides an interactive chat interface that allows users to ask
|
|
| 34 |
- ChromaDB for vector storage
|
| 35 |
- Supports PDF document processing
|
| 36 |
|
| 37 |
-
## Included
|
| 38 |
-
The
|
| 39 |
-
|
| 40 |
-
-
|
| 41 |
-
-
|
| 42 |
-
-
|
| 43 |
-
-
|
| 44 |
-
-
|
| 45 |
-
-
|
| 46 |
-
- [arXiv:2410.21228v1](https://arxiv.org/abs/2410.21228)
|
| 47 |
-
- [arXiv:2411.05059v2](https://arxiv.org/abs/2411.05059)
|
| 48 |
-
- [arXiv:2501.09223v1](https://arxiv.org/abs/2501.09223)
|
| 49 |
-
- [arXiv:2501.12948v1](https://arxiv.org/abs/2501.12948)
|
| 50 |
-
- [arXiv:2503.04872v1](https://arxiv.org/abs/2503.04872)
|
| 51 |
|
| 52 |
## Deployment
|
| 53 |
This application is hosted as a Hugging Face Space. Configuration details can be found in the [spaces config reference](https://huggingface.co/docs/hub/spaces-config-reference).
|
|
|
|
| 34 |
- ChromaDB for vector storage
|
| 35 |
- Supports PDF document processing
|
| 36 |
|
| 37 |
+
## Included Documents
|
| 38 |
+
The `pdf` directory contains IEA (International Energy Agency) reports and publications covering topics such as:
|
| 39 |
+
|
| 40 |
+
- Clean energy transitions and net zero pathways
|
| 41 |
+
- Renewable energy capacity and projections
|
| 42 |
+
- Electric vehicles and battery technologies
|
| 43 |
+
- Carbon capture, utilisation and storage (CCUS)
|
| 44 |
+
- Energy efficiency and critical minerals
|
| 45 |
+
- Regional energy profiles and policy recommendations
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 46 |
|
| 47 |
## Deployment
|
| 48 |
This application is hosted as a Hugging Face Space. Configuration details can be found in the [spaces config reference](https://huggingface.co/docs/hub/spaces-config-reference).
|
models.py
CHANGED
|
@@ -41,3 +41,5 @@ def create_embeddings():
|
|
| 41 |
encode_kwargs={"normalize_embeddings": True},
|
| 42 |
)
|
| 43 |
|
|
|
|
|
|
|
|
|
| 41 |
encode_kwargs={"normalize_embeddings": True},
|
| 42 |
)
|
| 43 |
|
| 44 |
+
|
| 45 |
+
|
qa_chain.py
CHANGED
|
@@ -103,7 +103,7 @@ Rewritten query (keywords and key phrases only, be concise):"""
|
|
| 103 |
|
| 104 |
return rewritten
|
| 105 |
except Exception as e:
|
| 106 |
-
|
| 107 |
return question
|
| 108 |
|
| 109 |
def rerank_documents(self, query, documents, top_k=RETRIEVER_K):
|
|
@@ -138,7 +138,7 @@ Rewritten query (keywords and key phrases only, be concise):"""
|
|
| 138 |
|
| 139 |
return [(doc, score) for doc, score in scored_docs[:top_k]]
|
| 140 |
except Exception as e:
|
| 141 |
-
|
| 142 |
# Fall back to original order
|
| 143 |
return [(doc, None) for doc in documents[:top_k]]
|
| 144 |
|
|
@@ -363,8 +363,9 @@ Rewritten query (keywords and key phrases only, be concise):"""
|
|
| 363 |
"hybrid_scores": hybrid_scores,
|
| 364 |
}
|
| 365 |
except Exception as e:
|
|
|
|
| 366 |
yield {
|
| 367 |
-
"chunk":
|
| 368 |
"source_documents": docs,
|
| 369 |
"docs_with_scores": docs_with_scores,
|
| 370 |
"rewritten_query": rewritten_query,
|
|
|
|
| 103 |
|
| 104 |
return rewritten
|
| 105 |
except Exception as e:
|
| 106 |
+
logger.warning(f"Query rewriting failed: {e}")
|
| 107 |
return question
|
| 108 |
|
| 109 |
def rerank_documents(self, query, documents, top_k=RETRIEVER_K):
|
|
|
|
| 138 |
|
| 139 |
return [(doc, score) for doc, score in scored_docs[:top_k]]
|
| 140 |
except Exception as e:
|
| 141 |
+
logger.warning(f"Re-ranking failed: {e}")
|
| 142 |
# Fall back to original order
|
| 143 |
return [(doc, None) for doc in documents[:top_k]]
|
| 144 |
|
|
|
|
| 363 |
"hybrid_scores": hybrid_scores,
|
| 364 |
}
|
| 365 |
except Exception as e:
|
| 366 |
+
logger.error(f"Stream error: {e}")
|
| 367 |
yield {
|
| 368 |
+
"chunk": "\n\n[An error occurred. Please try again.]",
|
| 369 |
"source_documents": docs,
|
| 370 |
"docs_with_scores": docs_with_scores,
|
| 371 |
"rewritten_query": rewritten_query,
|
tests/TEST_REVIEW.md
DELETED
|
@@ -1,370 +0,0 @@
|
|
| 1 |
-
# Critical Test Suite Review
|
| 2 |
-
|
| 3 |
-
## Executive Summary
|
| 4 |
-
|
| 5 |
-
**Current Status:** 98.28% code coverage with 119 tests passing β
|
| 6 |
-
|
| 7 |
-
**Overall Assessment:** The test suite is comprehensive and well-structured, but several important workflows and edge cases are missing that could impact production reliability.
|
| 8 |
-
|
| 9 |
-
---
|
| 10 |
-
|
| 11 |
-
## β
Well-Covered Areas
|
| 12 |
-
|
| 13 |
-
1. **Core Functionality**
|
| 14 |
-
- Unit tests for all major modules (config, models, utils, vectorstore, retrievers, qa_chain)
|
| 15 |
-
- Integration tests for RAG flow
|
| 16 |
-
- Edge cases for individual components
|
| 17 |
-
|
| 18 |
-
2. **Search Strategies**
|
| 19 |
-
- MMR, Similarity, and Hybrid search types
|
| 20 |
-
- Query rewriting and re-ranking
|
| 21 |
-
- Document filtering
|
| 22 |
-
|
| 23 |
-
3. **Error Handling**
|
| 24 |
-
- LLM errors
|
| 25 |
-
- Retriever errors
|
| 26 |
-
- Empty document scenarios
|
| 27 |
-
|
| 28 |
-
---
|
| 29 |
-
|
| 30 |
-
## β Missing Critical Workflows
|
| 31 |
-
|
| 32 |
-
### 1. **Multi-Turn Conversations** β οΈ HIGH PRIORITY
|
| 33 |
-
**Issue:** No tests for chat history context in RAG queries
|
| 34 |
-
|
| 35 |
-
**Missing Scenarios:**
|
| 36 |
-
- RAG query with previous conversation context
|
| 37 |
-
- Follow-up questions that reference previous answers
|
| 38 |
-
- Context accumulation across multiple turns
|
| 39 |
-
- Chat history limit enforcement (CHAT_HISTORY_LIMIT)
|
| 40 |
-
|
| 41 |
-
**Impact:** Users rely on conversational context for follow-up questions. Without testing, context may be lost or incorrectly formatted.
|
| 42 |
-
|
| 43 |
-
**Test Needed:**
|
| 44 |
-
```python
|
| 45 |
-
def test_rag_with_chat_history_context():
|
| 46 |
-
"""Test RAG query with multi-turn conversation."""
|
| 47 |
-
# First question
|
| 48 |
-
# Follow-up question that references first answer
|
| 49 |
-
# Verify context is properly included
|
| 50 |
-
```
|
| 51 |
-
|
| 52 |
-
---
|
| 53 |
-
|
| 54 |
-
### 2. **Mode Switching Workflows** β οΈ HIGH PRIORITY
|
| 55 |
-
**Issue:** No tests for switching between RAG and Vanilla modes
|
| 56 |
-
|
| 57 |
-
**Missing Scenarios:**
|
| 58 |
-
- Start with RAG, switch to Vanilla mid-conversation
|
| 59 |
-
- Start with Vanilla, switch to RAG mid-conversation
|
| 60 |
-
- Chat history preservation across mode switches
|
| 61 |
-
- UI state consistency during switches
|
| 62 |
-
|
| 63 |
-
**Impact:** Users may lose context or get confused when switching modes.
|
| 64 |
-
|
| 65 |
-
**Test Needed:**
|
| 66 |
-
```python
|
| 67 |
-
def test_mode_switching_preserves_history():
|
| 68 |
-
"""Test that chat history is preserved when switching modes."""
|
| 69 |
-
```
|
| 70 |
-
|
| 71 |
-
---
|
| 72 |
-
|
| 73 |
-
### 3. **Empty Vectorstore Scenarios** β οΈ MEDIUM PRIORITY
|
| 74 |
-
**Issue:** Limited testing of empty/initial state
|
| 75 |
-
|
| 76 |
-
**Missing Scenarios:**
|
| 77 |
-
- First-time user (no vectorstore exists)
|
| 78 |
-
- Vectorstore exists but is empty (no documents)
|
| 79 |
-
- User queries before any documents are loaded
|
| 80 |
-
- Graceful degradation when no documents available
|
| 81 |
-
|
| 82 |
-
**Impact:** Application may crash or show confusing errors to new users.
|
| 83 |
-
|
| 84 |
-
**Test Needed:**
|
| 85 |
-
```python
|
| 86 |
-
def test_rag_query_with_empty_vectorstore():
|
| 87 |
-
"""Test RAG query when no documents are available."""
|
| 88 |
-
# Should return empty results or helpful message
|
| 89 |
-
```
|
| 90 |
-
|
| 91 |
-
---
|
| 92 |
-
|
| 93 |
-
### 4. **Document Update Workflow** β οΈ MEDIUM PRIORITY
|
| 94 |
-
**Issue:** Limited testing of adding new documents to existing vectorstore
|
| 95 |
-
|
| 96 |
-
**Missing Scenarios:**
|
| 97 |
-
- Adding new PDFs to existing vectorstore
|
| 98 |
-
- Updating vectorstore with duplicate documents
|
| 99 |
-
- Partial document loading failures
|
| 100 |
-
- Concurrent document additions
|
| 101 |
-
|
| 102 |
-
**Impact:** Users may not see new documents or experience data corruption.
|
| 103 |
-
|
| 104 |
-
**Test Needed:**
|
| 105 |
-
```python
|
| 106 |
-
def test_vectorstore_update_with_new_documents():
|
| 107 |
-
"""Test adding new documents to existing vectorstore."""
|
| 108 |
-
# Verify new documents are indexed
|
| 109 |
-
# Verify old documents remain
|
| 110 |
-
# Verify no duplicates
|
| 111 |
-
```
|
| 112 |
-
|
| 113 |
-
---
|
| 114 |
-
|
| 115 |
-
### 5. **Network/API Failure Scenarios** β οΈ HIGH PRIORITY
|
| 116 |
-
**Issue:** Limited testing of external service failures
|
| 117 |
-
|
| 118 |
-
**Missing Scenarios:**
|
| 119 |
-
- LLM server unavailable/timeout
|
| 120 |
-
- Embedding model download failure
|
| 121 |
-
- ChromaDB connection failures
|
| 122 |
-
- Network interruptions during streaming
|
| 123 |
-
- Retry logic for transient failures
|
| 124 |
-
|
| 125 |
-
**Impact:** Application may hang or crash when external services fail.
|
| 126 |
-
|
| 127 |
-
**Test Needed:**
|
| 128 |
-
```python
|
| 129 |
-
def test_llm_server_unavailable():
|
| 130 |
-
"""Test graceful handling when LLM server is down."""
|
| 131 |
-
# Should show user-friendly error
|
| 132 |
-
# Should not crash application
|
| 133 |
-
```
|
| 134 |
-
|
| 135 |
-
---
|
| 136 |
-
|
| 137 |
-
### 6. **Input Validation & Edge Cases** β οΈ MEDIUM PRIORITY
|
| 138 |
-
**Issue:** Limited testing of invalid inputs
|
| 139 |
-
|
| 140 |
-
**Missing Scenarios:**
|
| 141 |
-
- Very long queries (>10k characters)
|
| 142 |
-
- Empty queries (whitespace only)
|
| 143 |
-
- Special characters in queries
|
| 144 |
-
- Invalid document filter selections
|
| 145 |
-
- Malformed chat history
|
| 146 |
-
- Unicode/emoji in queries
|
| 147 |
-
|
| 148 |
-
**Impact:** Application may crash or behave unexpectedly with edge case inputs.
|
| 149 |
-
|
| 150 |
-
**Test Needed:**
|
| 151 |
-
```python
|
| 152 |
-
def test_very_long_query():
|
| 153 |
-
"""Test handling of extremely long queries."""
|
| 154 |
-
|
| 155 |
-
def test_empty_whitespace_query():
|
| 156 |
-
"""Test handling of whitespace-only queries."""
|
| 157 |
-
|
| 158 |
-
def test_invalid_document_filter():
|
| 159 |
-
"""Test handling of invalid document filter selection."""
|
| 160 |
-
```
|
| 161 |
-
|
| 162 |
-
---
|
| 163 |
-
|
| 164 |
-
### 7. **Hybrid Search Parameter Variations** β οΈ LOW PRIORITY
|
| 165 |
-
**Issue:** Limited testing of hybrid alpha parameter
|
| 166 |
-
|
| 167 |
-
**Missing Scenarios:**
|
| 168 |
-
- Hybrid search with alpha=0.0 (pure keyword)
|
| 169 |
-
- Hybrid search with alpha=1.0 (pure semantic)
|
| 170 |
-
- Hybrid search with various alpha values (0.1, 0.5, 0.9)
|
| 171 |
-
- Score fusion correctness at boundaries
|
| 172 |
-
|
| 173 |
-
**Impact:** Users may not get optimal results with different alpha settings.
|
| 174 |
-
|
| 175 |
-
**Test Needed:**
|
| 176 |
-
```python
|
| 177 |
-
def test_hybrid_search_alpha_boundaries():
|
| 178 |
-
"""Test hybrid search with extreme alpha values."""
|
| 179 |
-
```
|
| 180 |
-
|
| 181 |
-
---
|
| 182 |
-
|
| 183 |
-
### 8. **Streaming Edge Cases** β οΈ MEDIUM PRIORITY
|
| 184 |
-
**Issue:** Limited testing of streaming failures
|
| 185 |
-
|
| 186 |
-
**Missing Scenarios:**
|
| 187 |
-
- Stream interruption mid-response
|
| 188 |
-
- Partial stream completion
|
| 189 |
-
- Multiple concurrent streams
|
| 190 |
-
- Stream timeout handling
|
| 191 |
-
- Memory leaks during long streams
|
| 192 |
-
|
| 193 |
-
**Impact:** Users may experience incomplete responses or resource issues.
|
| 194 |
-
|
| 195 |
-
**Test Needed:**
|
| 196 |
-
```python
|
| 197 |
-
def test_stream_interruption():
|
| 198 |
-
"""Test handling of interrupted streams."""
|
| 199 |
-
|
| 200 |
-
def test_concurrent_streams():
|
| 201 |
-
"""Test multiple concurrent streaming requests."""
|
| 202 |
-
```
|
| 203 |
-
|
| 204 |
-
---
|
| 205 |
-
|
| 206 |
-
### 9. **PDF Loading & Processing** β οΈ MEDIUM PRIORITY
|
| 207 |
-
**Issue:** Limited testing of PDF processing edge cases
|
| 208 |
-
|
| 209 |
-
**Missing Scenarios:**
|
| 210 |
-
- Corrupted PDF files
|
| 211 |
-
- Password-protected PDFs
|
| 212 |
-
- Very large PDF files (>100MB)
|
| 213 |
-
- PDFs with no extractable text
|
| 214 |
-
- PDFs with images only
|
| 215 |
-
- Multiple PDFs with same filename
|
| 216 |
-
|
| 217 |
-
**Impact:** Application may fail silently or crash when processing problematic PDFs.
|
| 218 |
-
|
| 219 |
-
**Test Needed:**
|
| 220 |
-
```python
|
| 221 |
-
def test_corrupted_pdf_handling():
|
| 222 |
-
"""Test handling of corrupted PDF files."""
|
| 223 |
-
|
| 224 |
-
def test_large_pdf_processing():
|
| 225 |
-
"""Test processing of very large PDF files."""
|
| 226 |
-
```
|
| 227 |
-
|
| 228 |
-
---
|
| 229 |
-
|
| 230 |
-
### 10. **Vectorstore Persistence & Recovery** β οΈ LOW PRIORITY
|
| 231 |
-
**Issue:** No tests for persistence and recovery
|
| 232 |
-
|
| 233 |
-
**Missing Scenarios:**
|
| 234 |
-
- Vectorstore corruption detection
|
| 235 |
-
- Recovery from corrupted vectorstore
|
| 236 |
-
- Backup and restore workflows
|
| 237 |
-
- Migration between vectorstore versions
|
| 238 |
-
|
| 239 |
-
**Impact:** Users may lose their indexed documents or experience data corruption.
|
| 240 |
-
|
| 241 |
-
**Test Needed:**
|
| 242 |
-
```python
|
| 243 |
-
def test_vectorstore_corruption_recovery():
|
| 244 |
-
"""Test recovery from corrupted vectorstore."""
|
| 245 |
-
```
|
| 246 |
-
|
| 247 |
-
---
|
| 248 |
-
|
| 249 |
-
### 11. **UI/UX Workflows** β οΈ MEDIUM PRIORITY
|
| 250 |
-
**Issue:** Limited testing of UI interaction flows
|
| 251 |
-
|
| 252 |
-
**Missing Scenarios:**
|
| 253 |
-
- Clear button functionality
|
| 254 |
-
- Example question selection
|
| 255 |
-
- RAG toggle state persistence
|
| 256 |
-
- Search type change during active query
|
| 257 |
-
- Document filter change during active query
|
| 258 |
-
- Context panel visibility toggling
|
| 259 |
-
|
| 260 |
-
**Impact:** Users may experience UI bugs or confusion.
|
| 261 |
-
|
| 262 |
-
**Test Needed:**
|
| 263 |
-
```python
|
| 264 |
-
def test_ui_clear_functionality():
|
| 265 |
-
"""Test clear button resets all state correctly."""
|
| 266 |
-
|
| 267 |
-
def test_ui_state_consistency():
|
| 268 |
-
"""Test UI state remains consistent during operations."""
|
| 269 |
-
```
|
| 270 |
-
|
| 271 |
-
---
|
| 272 |
-
|
| 273 |
-
### 12. **Performance & Scalability** β οΈ LOW PRIORITY
|
| 274 |
-
**Issue:** No performance tests
|
| 275 |
-
|
| 276 |
-
**Missing Scenarios:**
|
| 277 |
-
- Query latency with large document sets
|
| 278 |
-
- Memory usage with many documents
|
| 279 |
-
- Concurrent user handling
|
| 280 |
-
- Large chat history performance
|
| 281 |
-
|
| 282 |
-
**Impact:** Application may become slow or unresponsive with scale.
|
| 283 |
-
|
| 284 |
-
**Test Needed:**
|
| 285 |
-
```python
|
| 286 |
-
def test_query_performance_large_dataset():
|
| 287 |
-
"""Test query performance with large document sets."""
|
| 288 |
-
```
|
| 289 |
-
|
| 290 |
-
---
|
| 291 |
-
|
| 292 |
-
## π Additional Observations
|
| 293 |
-
|
| 294 |
-
### Test Organization
|
| 295 |
-
- β
Good separation of unit, integration, and edge case tests
|
| 296 |
-
- β
Clear naming conventions
|
| 297 |
-
- β οΈ Some test files could be consolidated (multiple qa_chain test files)
|
| 298 |
-
|
| 299 |
-
### Test Quality
|
| 300 |
-
- β
Good use of fixtures and mocks
|
| 301 |
-
- β
Comprehensive assertions
|
| 302 |
-
- β οΈ Some tests are too focused on implementation details rather than behavior
|
| 303 |
-
|
| 304 |
-
### Coverage Gaps
|
| 305 |
-
- **qa_chain.py lines 269-274:** Similarity search document matching (edge case)
|
| 306 |
-
- **retrievers.py lines 66, 128, 179-185:** Hybrid search edge cases
|
| 307 |
-
|
| 308 |
-
---
|
| 309 |
-
|
| 310 |
-
## π Recommended Action Items
|
| 311 |
-
|
| 312 |
-
### Immediate (Before Production)
|
| 313 |
-
1. β
Add multi-turn conversation tests
|
| 314 |
-
2. β
Add mode switching tests
|
| 315 |
-
3. β
Add empty vectorstore tests
|
| 316 |
-
4. β
Add network failure tests
|
| 317 |
-
5. β
Add input validation tests
|
| 318 |
-
|
| 319 |
-
### Short-term (Next Sprint)
|
| 320 |
-
6. β
Add document update workflow tests
|
| 321 |
-
7. β
Add streaming edge case tests
|
| 322 |
-
8. β
Add PDF processing edge case tests
|
| 323 |
-
9. β
Add UI workflow tests
|
| 324 |
-
|
| 325 |
-
### Long-term (Future Enhancements)
|
| 326 |
-
10. β
Add performance tests
|
| 327 |
-
11. β
Add vectorstore persistence tests
|
| 328 |
-
12. β
Add hybrid search parameter variation tests
|
| 329 |
-
|
| 330 |
-
---
|
| 331 |
-
|
| 332 |
-
## π― Priority Matrix
|
| 333 |
-
|
| 334 |
-
| Workflow | Priority | Impact | Effort | Status |
|
| 335 |
-
|----------|----------|--------|--------|--------|
|
| 336 |
-
| Multi-turn conversations | HIGH | HIGH | MEDIUM | β Missing |
|
| 337 |
-
| Mode switching | HIGH | HIGH | LOW | β Missing |
|
| 338 |
-
| Network failures | HIGH | HIGH | MEDIUM | β οΈ Partial |
|
| 339 |
-
| Empty vectorstore | MEDIUM | MEDIUM | LOW | β οΈ Partial |
|
| 340 |
-
| Input validation | MEDIUM | MEDIUM | LOW | β οΈ Partial |
|
| 341 |
-
| Document updates | MEDIUM | MEDIUM | MEDIUM | β οΈ Partial |
|
| 342 |
-
| Streaming edge cases | MEDIUM | MEDIUM | MEDIUM | β οΈ Partial |
|
| 343 |
-
| PDF processing | MEDIUM | MEDIUM | MEDIUM | β οΈ Partial |
|
| 344 |
-
| UI workflows | MEDIUM | LOW | LOW | β οΈ Partial |
|
| 345 |
-
| Performance | LOW | LOW | HIGH | β Missing |
|
| 346 |
-
| Vectorstore persistence | LOW | LOW | HIGH | β Missing |
|
| 347 |
-
|
| 348 |
-
---
|
| 349 |
-
|
| 350 |
-
## π‘ Recommendations
|
| 351 |
-
|
| 352 |
-
1. **Focus on User Journeys:** Add end-to-end tests that simulate real user workflows
|
| 353 |
-
2. **Error Resilience:** Expand error handling tests to cover all failure modes
|
| 354 |
-
3. **Integration Testing:** Add more integration tests that test multiple components together
|
| 355 |
-
4. **Performance Baseline:** Establish performance benchmarks for critical paths
|
| 356 |
-
5. **Test Documentation:** Document test scenarios and their business value
|
| 357 |
-
|
| 358 |
-
---
|
| 359 |
-
|
| 360 |
-
## Conclusion
|
| 361 |
-
|
| 362 |
-
The test suite provides excellent code coverage (98.28%) and covers most unit-level functionality well. However, several critical user workflows and edge cases are missing, particularly around:
|
| 363 |
-
|
| 364 |
-
- **Multi-turn conversations** (critical for RAG use case)
|
| 365 |
-
- **Mode switching** (core feature)
|
| 366 |
-
- **Error resilience** (production readiness)
|
| 367 |
-
- **Input validation** (user experience)
|
| 368 |
-
|
| 369 |
-
Addressing these gaps will significantly improve production reliability and user experience.
|
| 370 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
tests/__init__.py
CHANGED
|
@@ -1,2 +1,4 @@
|
|
| 1 |
"""Test suite for the RAG application."""
|
| 2 |
|
|
|
|
|
|
|
|
|
| 1 |
"""Test suite for the RAG application."""
|
| 2 |
|
| 3 |
+
|
| 4 |
+
|
tests/conftest.py
CHANGED
|
@@ -131,3 +131,5 @@ def mock_hybrid_results():
|
|
| 131 |
},
|
| 132 |
]
|
| 133 |
|
|
|
|
|
|
|
|
|
| 131 |
},
|
| 132 |
]
|
| 133 |
|
| 134 |
+
|
| 135 |
+
|
tests/test_cli.py
CHANGED
|
@@ -215,3 +215,5 @@ def test_cli_main_rag_error(
|
|
| 215 |
captured = capsys.readouterr()
|
| 216 |
assert "Error" in captured.out
|
| 217 |
|
|
|
|
|
|
|
|
|
| 215 |
captured = capsys.readouterr()
|
| 216 |
assert "Error" in captured.out
|
| 217 |
|
| 218 |
+
|
| 219 |
+
|
tests/test_config.py
CHANGED
|
@@ -54,3 +54,5 @@ def test_environment_variables():
|
|
| 54 |
assert isinstance(os.getenv("CHROMA_PATH", "vectorstore"), str)
|
| 55 |
assert isinstance(os.getenv("PDF_PATH", "pdf"), str)
|
| 56 |
|
|
|
|
|
|
|
|
|
| 54 |
assert isinstance(os.getenv("CHROMA_PATH", "vectorstore"), str)
|
| 55 |
assert isinstance(os.getenv("PDF_PATH", "pdf"), str)
|
| 56 |
|
| 57 |
+
|
| 58 |
+
|
tests/test_models.py
CHANGED
|
@@ -43,3 +43,5 @@ def test_create_embeddings(mock_embeddings):
|
|
| 43 |
assert call_kwargs["encode_kwargs"]["normalize_embeddings"] is True
|
| 44 |
assert result == mock_instance
|
| 45 |
|
|
|
|
|
|
|
|
|
| 43 |
assert call_kwargs["encode_kwargs"]["normalize_embeddings"] is True
|
| 44 |
assert result == mock_instance
|
| 45 |
|
| 46 |
+
|
| 47 |
+
|
tests/test_qa_chain.py
CHANGED
|
@@ -241,7 +241,7 @@ def test_stream_error(mock_format_history, mock_create_llm, qa_chain_wrapper, mo
|
|
| 241 |
|
| 242 |
results = list(qa_chain_wrapper.stream(inputs))
|
| 243 |
assert len(results) > 0
|
| 244 |
-
assert "
|
| 245 |
|
| 246 |
|
| 247 |
def test_create_qa_chain(mock_vectorstore):
|
|
|
|
| 241 |
|
| 242 |
results = list(qa_chain_wrapper.stream(inputs))
|
| 243 |
assert len(results) > 0
|
| 244 |
+
assert "error occurred" in results[0]["chunk"]
|
| 245 |
|
| 246 |
|
| 247 |
def test_create_qa_chain(mock_vectorstore):
|
tests/test_qa_chain_final.py
CHANGED
|
@@ -64,3 +64,5 @@ def test_stream_similarity_exact_match(mock_format_history, mock_create_llm, qa_
|
|
| 64 |
# Verify that the matching logic was executed (lines 269-274)
|
| 65 |
assert results[0].get("docs_with_scores") is not None
|
| 66 |
|
|
|
|
|
|
|
|
|
| 64 |
# Verify that the matching logic was executed (lines 269-274)
|
| 65 |
assert results[0].get("docs_with_scores") is not None
|
| 66 |
|
| 67 |
+
|
| 68 |
+
|
tests/test_retrievers.py
CHANGED
|
@@ -137,3 +137,5 @@ def test_hybrid_search_semantic_error(mock_vectorstore, sample_documents):
|
|
| 137 |
# Should still return results from BM25
|
| 138 |
assert isinstance(results, list)
|
| 139 |
|
|
|
|
|
|
|
|
|
| 137 |
# Should still return results from BM25
|
| 138 |
assert isinstance(results, list)
|
| 139 |
|
| 140 |
+
|
| 141 |
+
|
tests/test_retrievers_edge_cases.py
CHANGED
|
@@ -77,3 +77,5 @@ def test_hybrid_search_negative_distance(mock_vectorstore):
|
|
| 77 |
|
| 78 |
assert len(results) > 0
|
| 79 |
|
|
|
|
|
|
|
|
|
| 77 |
|
| 78 |
assert len(results) > 0
|
| 79 |
|
| 80 |
+
|
| 81 |
+
|
tests/test_utils.py
CHANGED
|
@@ -131,3 +131,5 @@ def test_format_context_with_hybrid_scores(sample_documents):
|
|
| 131 |
assert "s:" in result # Semantic score
|
| 132 |
assert "k:" in result # Keyword score
|
| 133 |
|
|
|
|
|
|
|
|
|
| 131 |
assert "s:" in result # Semantic score
|
| 132 |
assert "k:" in result # Keyword score
|
| 133 |
|
| 134 |
+
|
| 135 |
+
|
tests/test_utils_edge_cases.py
CHANGED
|
@@ -43,3 +43,5 @@ def test_format_context_no_scores():
|
|
| 43 |
assert "Test content" in result
|
| 44 |
assert "β" in result # First chunk should be highlighted by default
|
| 45 |
|
|
|
|
|
|
|
|
|
| 43 |
assert "Test content" in result
|
| 44 |
assert "β" in result # First chunk should be highlighted by default
|
| 45 |
|
| 46 |
+
|
| 47 |
+
|
tests/test_vectorstore.py
CHANGED
|
@@ -182,3 +182,5 @@ def test_create_new_vectorstore(mock_chroma, mock_loader, mock_get_pdfs, mock_em
|
|
| 182 |
assert result == mock_vectorstore
|
| 183 |
mock_chroma.from_documents.assert_called_once()
|
| 184 |
|
|
|
|
|
|
|
|
|
| 182 |
assert result == mock_vectorstore
|
| 183 |
mock_chroma.from_documents.assert_called_once()
|
| 184 |
|
| 185 |
+
|
| 186 |
+
|
utils.py
CHANGED
|
@@ -143,3 +143,5 @@ def format_context_with_highlight(
|
|
| 143 |
|
| 144 |
return query_info + sources_header + "\n\n".join(formatted_chunks)
|
| 145 |
|
|
|
|
|
|
|
|
|
| 143 |
|
| 144 |
return query_info + sources_header + "\n\n".join(formatted_chunks)
|
| 145 |
|
| 146 |
+
|
| 147 |
+
|