Skip to content

Commit 78dfcee

Browse files
authored
Merge pull request #1 from brylie/improve-maintainability
Refactor code structure and enhance documentation
2 parents 7cf3f75 + ef2239d commit 78dfcee

29 files changed

Lines changed: 3572 additions & 2927 deletions

CONTRIBUTING.md

Lines changed: 196 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,19 @@ Thank you for considering contributing to Tapio Assistant! This document provide
1818
- [Testing Guidelines](#testing-guidelines)
1919
- [Running Tests](#running-tests)
2020
- [Code Coverage](#code-coverage)
21+
- [Test Categories](#test-categories)
22+
- [Test Fixtures](#test-fixtures)
2123
- [Project Structure](#project-structure)
24+
- [Programmatic API](#programmatic-api)
25+
- [Using Factory Pattern (Recommended)](#using-factory-pattern-recommended)
26+
- [Manual Dependency Injection (Advanced)](#manual-dependency-injection-advanced)
27+
- [Key Components](#key-components)
2228
- [Configuration System](#configuration-system)
29+
- [Default Settings](#default-settings)
30+
- [Site Configurations](#site-configurations)
31+
- [Configuration Structure](#configuration-structure)
32+
- [Required vs Optional Fields](#required-vs-optional-fields)
33+
- [Adding New Sites](#adding-new-sites)
2334
- [Ollama for LLM Inference](#ollama-for-llm-inference)
2435
- [Pull Request Process](#pull-request-process)
2536

@@ -241,7 +252,7 @@ uv run pytest
241252

242253
### Code Coverage
243254

244-
We aim for high test coverage. When submitting code:
255+
We aim for high test coverage (minimum 80%). When submitting code:
245256

246257
1. Check your coverage with:
247258

@@ -263,18 +274,112 @@ uv run pytest --cov=tapio.utils tests/utils/
263274

264275
Aim for at least 80% coverage for new code. The HTML coverage report can be found in the `htmlcov` directory. Open `htmlcov/index.html` in your browser to view it.
265276

277+
### Test Categories
278+
279+
We maintain different types of tests:
280+
281+
**Unit Tests** - Fast, isolated tests with mocked dependencies:
282+
```bash
283+
uv run pytest -m "not integration"
284+
```
285+
286+
**Integration Tests** - Tests using real components (marked with `@pytest.mark.integration`):
287+
```bash
288+
uv run pytest -m integration
289+
```
290+
291+
**All Tests**:
292+
```bash
293+
uv run pytest
294+
```
295+
296+
### Test Fixtures
297+
298+
Common mock fixtures are available in `tests/conftest.py`:
299+
- `mock_embeddings` - Mocked HuggingFace embeddings
300+
- `mock_chroma_store` - Mocked ChromaDB vector store
301+
- `mock_llm_service` - Mocked LLM service
302+
- `mock_doc_retrieval_service` - Mocked document retrieval service
303+
- `mock_rag_orchestrator` - Mocked RAG orchestrator
304+
305+
Use these fixtures in your tests for consistent mocking:
306+
```python
307+
def test_my_feature(mock_rag_orchestrator):
308+
# Test uses mocked orchestrator
309+
pass
310+
```
311+
266312
## Project Structure
267313

268314
The project has been designed with a clear separation of concerns:
269315

270316
- `crawler/`: Module responsible for crawling websites and saving HTML content
271317
- `parsers/`: Module responsible for parsing HTML content into structured formats
272318
- `vectorstore/`: Module responsible for vectorizing content and storing in ChromaDB
319+
- `services/`: RAG orchestration and LLM services
273320
- `config/`: Configuration settings for the project
274-
- `gradio_app.py`: Gradio interface for the RAG chatbot
321+
- `app.py`: Gradio interface for the RAG chatbot
322+
- `cli.py`: Command-line interface
323+
- `factories.py`: Factory classes for dependency injection
275324
- `utils/`: Utility modules for embedding generation, markdown processing, etc.
276325
- `tests/`: Test suite for all modules
277326

327+
## Programmatic API
328+
329+
For developers who want to use Tapio as a library or extend its functionality:
330+
331+
### Using Factory Pattern (Recommended)
332+
333+
```python
334+
from tapio import RAGConfig, RAGOrchestratorFactory
335+
336+
# Create configuration
337+
config = RAGConfig(
338+
collection_name="my_docs",
339+
persist_directory="./db",
340+
llm_model_name="llama3.2",
341+
max_tokens=1024,
342+
num_results=5
343+
)
344+
345+
# Create orchestrator using factory
346+
factory = RAGOrchestratorFactory(config)
347+
orchestrator = factory.create_orchestrator()
348+
349+
# Query the system
350+
response, documents = orchestrator.query("What are the visa requirements?")
351+
print(response)
352+
```
353+
354+
### Manual Dependency Injection (Advanced)
355+
356+
For full control over component creation:
357+
358+
```python
359+
from langchain_huggingface import HuggingFaceEmbeddings
360+
from tapio.vectorstore.chroma_store import ChromaStore
361+
from tapio.services.document_retrieval_service import DocumentRetrievalService
362+
from tapio.services.llm_service import LLMService
363+
from tapio.services.rag_orchestrator import RAGOrchestrator
364+
365+
# Create dependencies
366+
embeddings = HuggingFaceEmbeddings(model_name="all-MiniLM-L6-v2")
367+
chroma_store = ChromaStore("my_docs", embeddings, "./db")
368+
doc_service = DocumentRetrievalService(chroma_store, num_results=5)
369+
llm_service = LLMService(model_name="llama3.2", max_tokens=1024)
370+
371+
# Create orchestrator
372+
orchestrator = RAGOrchestrator(doc_service, llm_service)
373+
```
374+
375+
### Key Components
376+
377+
- **RAGOrchestrator**: Main orchestrator that coordinates document retrieval and LLM generation
378+
- **DocumentRetrievalService**: Handles vector-based document retrieval
379+
- **LLMService**: Manages LLM interactions via Ollama
380+
- **ChromaStore**: Vector database abstraction layer
381+
- **Factories**: Simplify dependency wiring with sensible defaults
382+
278383
## Configuration System
279384

280385
The application uses a centralized configuration system:
@@ -291,6 +396,95 @@ When adding new features that require configuration values:
291396
3. Avoid hardcoding values that might need to change in the future
292397
4. Use descriptive keys for configuration values
293398

399+
### Default Settings
400+
401+
Centralized configuration in `tapio/config/settings.py`:
402+
403+
```python
404+
DEFAULT_DIRS = {
405+
"CRAWLED_DIR": "content/crawled", # HTML storage
406+
"PARSED_DIR": "content/parsed", # Markdown storage
407+
"CHROMA_DIR": "chroma_db", # Vector database
408+
}
409+
410+
DEFAULT_CHROMA_COLLECTION = "tapio" # ChromaDB collection name
411+
DEFAULT_EMBEDDING_MODEL = "all-MiniLM-L6-v2"
412+
DEFAULT_LLM_MODEL = "llama3.2"
413+
DEFAULT_MAX_TOKENS = 1024
414+
DEFAULT_NUM_RESULTS = 5
415+
```
416+
417+
## Site Configurations
418+
419+
Site configurations define how to crawl and parse specific websites. They're stored in `tapio/config/site_configs.yaml` and used by both crawl and parse commands.
420+
421+
### Configuration Structure
422+
423+
```yaml
424+
sites:
425+
migri:
426+
base_url: "https://migri.fi" # Used for crawling and converting relative links
427+
description: "Finnish Immigration Service website"
428+
crawler_config: # Crawling behavior
429+
delay_between_requests: 1.0 # Seconds between requests
430+
max_concurrent: 3 # Concurrent request limit
431+
parser_config: # Parser-specific configuration
432+
title_selector: "//title" # XPath for page titles
433+
content_selectors: # Priority-ordered content extraction
434+
- '//div[@id="main-content"]'
435+
- "//main"
436+
- "//article"
437+
- '//div[@class="content"]'
438+
fallback_to_body: true # Use <body> if selectors fail
439+
markdown_config: # HTML-to-Markdown options
440+
ignore_links: false
441+
body_width: 0 # No text wrapping
442+
protect_links: true
443+
unicode_snob: true
444+
ignore_images: false
445+
ignore_tables: false
446+
```
447+
448+
### Required vs Optional Fields
449+
450+
**Required:**
451+
- `base_url` - Base URL for the site (used for crawling and link resolution)
452+
453+
**Optional (with defaults):**
454+
- `description` - Human-readable description
455+
- `parser_config` - Parser-specific settings (uses defaults if omitted)
456+
- `title_selector` - Page title XPath (default: "//title")
457+
- `content_selectors` - XPath selectors for content extraction (default: ["//main", "//article", "//body"])
458+
- `fallback_to_body` - Use full-body content if selectors fail (default: true)
459+
- `markdown_config` - HTML conversion settings (uses defaults if omitted)
460+
- `crawler_config` - Crawling behavior settings (uses defaults if omitted)
461+
- `delay_between_requests` - Delay between requests in seconds (default: 1.0)
462+
- `max_concurrent` - Maximum concurrent requests (default: 5)
463+
464+
### Adding New Sites
465+
466+
1. Analyze the target website's structure
467+
2. Identify XPath selectors for content extraction
468+
3. Add configuration to `site_configs.yaml`:
469+
470+
```yaml
471+
sites:
472+
my_site:
473+
base_url: "https://example.com"
474+
description: "Example site configuration"
475+
parser_config:
476+
content_selectors:
477+
- '//div[@class="main-content"]'
478+
```
479+
480+
4. Use with commands:
481+
```bash
482+
uv run -m tapio.cli crawl my_site
483+
uv run -m tapio.cli parse my_site
484+
uv run -m tapio.cli vectorize
485+
uv run -m tapio.cli tapio-app
486+
```
487+
294488
## Ollama for LLM Inference
295489

296490
We use Ollama for local LLM inference.

README.md

Lines changed: 1 addition & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -90,92 +90,7 @@ To view detailed site configurations:
9090
uv run -m tapio.cli list-sites --verbose
9191
```
9292

93-
## Site Configurations
94-
95-
Site configurations define how to crawl and parse specific websites. They're stored in `tapio/config/site_configs.yaml` and used by both crawl and parse commands.
96-
97-
### Configuration Structure
98-
99-
```yaml
100-
sites:
101-
migri:
102-
base_url: "https://migri.fi" # Used for crawling and converting relative links
103-
description: "Finnish Immigration Service website"
104-
crawler_config: # Crawling behavior
105-
delay_between_requests: 1.0 # Seconds between requests
106-
max_concurrent: 3 # Concurrent request limit
107-
parser_config: # Parser-specific configuration
108-
title_selector: "//title" # XPath for page titles
109-
content_selectors: # Priority-ordered content extraction
110-
- '//div[@id="main-content"]'
111-
- "//main"
112-
- "//article"
113-
- '//div[@class="content"]'
114-
fallback_to_body: true # Use <body> if selectors fail
115-
markdown_config: # HTML-to-Markdown options
116-
ignore_links: false
117-
body_width: 0 # No text wrapping
118-
protect_links: true
119-
unicode_snob: true
120-
ignore_images: false
121-
ignore_tables: false
122-
```
123-
124-
### Required vs Optional Fields
125-
126-
**Required:**
127-
- `base_url` - Base URL for the site (used for crawling and link resolution)
128-
129-
**Optional (with defaults):**
130-
- `description` - Human-readable description
131-
- `parser_config` - Parser-specific settings (uses defaults if omitted)
132-
- `title_selector` - Page title XPath (default: "//title")
133-
- `content_selectors` - XPath selectors for content extraction (default: ["//main", "//article", "//body"])
134-
- `fallback_to_body` - Use full body content if selectors fail (default: true)
135-
- `markdown_config` - HTML conversion settings (uses defaults if omitted)
136-
- `crawler_config` - Crawling behavior settings (uses defaults if omitted)
137-
- `delay_between_requests` - Delay between requests in seconds (default: 1.0)
138-
- `max_concurrent` - Maximum concurrent requests (default: 5)
139-
140-
### Adding New Sites
141-
142-
1. Analyze the target website's structure
143-
2. Identify XPath selectors for content extraction
144-
3. Add configuration to `site_configs.yaml`:
145-
146-
```yaml
147-
sites:
148-
my_site:
149-
base_url: "https://example.com"
150-
description: "Example site configuration"
151-
parser_config:
152-
content_selectors:
153-
- '//div[@class="main-content"]'
154-
```
155-
156-
4. Use with commands:
157-
```bash
158-
uv run -m tapio.cli crawl my_site
159-
uv run -m tapio.cli parse my_site
160-
uv run -m tapio.cli vectorize
161-
uv run -m tapio.cli tapio-app
162-
```
163-
164-
## Configuration
165-
166-
Tapio uses centralized configuration in `tapio/config/settings.py`:
167-
168-
```python
169-
DEFAULT_DIRS = {
170-
"CRAWLED_DIR": "content/crawled", # HTML storage
171-
"PARSED_DIR": "content/parsed", # Markdown storage
172-
"CHROMA_DIR": "chroma_db", # Vector database
173-
}
174-
175-
DEFAULT_CHROMA_COLLECTION = "tapio" # ChromaDB collection name
176-
```
177-
178-
Site-specific configurations are in `tapio/config/site_configs.yaml` and automatically handle content extraction and directory organization based on the site's domain.
93+
For technical details on site configurations, programmatic API usage, and adding new sites, see [CONTRIBUTING.md](CONTRIBUTING.md).
17994

18095
## Contributing
18196

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[project]
22
name = "tapio"
3-
version = "0.1.0"
3+
version = "2.0.0"
44
description = "An assistant for Finnish immigrants"
55
readme = "README.md"
66
requires-python = ">=3.10"

pytest.ini

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,7 @@ filterwarnings =
55
ignore::DeprecationWarning:websockets.legacy:
66
ignore::DeprecationWarning:.*:
77
ignore::DeprecationWarning:gradio.utils:
8+
9+
markers =
10+
integration: Integration tests that use real components (slower, may download models)
11+

tapio/__init__.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,9 @@
11
"""This file initializes the tapio package."""
2+
3+
from tapio.config.config_models import RAGConfig
4+
from tapio.factories import RAGOrchestratorFactory
5+
6+
__all__ = [
7+
"RAGConfig",
8+
"RAGOrchestratorFactory",
9+
]

0 commit comments

Comments
 (0)