168 lines
7.8 KiB
Markdown
168 lines
7.8 KiB
Markdown
# ChatterMate Enhanced Website Knowledge Base
|
|||
|
|
|
||
|
|
This module provides an enhanced website knowledge extraction system that significantly improves content extraction from web pages compared to the default implementation.
|
||
|
|
|
||
|
|
## Key Features
|
||
|
|
|
||
|
|
- **Multi-strategy content extraction**: Uses multiple strategies to extract the most relevant content from web pages.
|
||
|
|
- **Robust error handling**: Implements retries with exponential backoff for failed requests.
|
||
|
|
- **Text density analysis**: Can identify important content based on paragraph density when standard selectors fail.
|
||
|
|
- **Smart content cleaning**: Automatically removes boilerplate, navigation, ads, and other non-content elements.
|
||
|
|
- **Configurable parameters**: Allows customization of crawl depth, number of links, timeouts, etc.
|
||
|
|
- **High-performance parallel embedding**: Embeds documents in parallel during crawling to maximize throughput.
|
||
|
|
- **Optimized database insertion**: Preserves embeddings to avoid redundant work during vector database operations.
|
||
|
|
|
||
|
|
## Usage
|
||
|
|
|
||
|
|
### Basic Usage
|
||
|
|
|
||
|
|
```python
|
||
|
|
from app.knowledge.enhanced_website_kb import EnhancedWebsiteKnowledgeBase
|
||
|
|
from agno.vectordb.pgvector import PgVector
|
||
|
|
|
||
|
|
# Initialize vector database
|
||
|
|
vector_db = PgVector(
|
||
|
|
table_name="your_table",
|
||
|
|
db_url="your_db_url",
|
||
|
|
schema="your_schema"
|
||
|
|
)
|
||
|
|
|
||
|
|
# Create knowledge base
|
||
|
|
kb = EnhancedWebsiteKnowledgeBase(
|
||
|
|
urls=["https://example.com"], # List of URLs to crawl
|
||
|
|
max_depth=3, # How deep to crawl (default: 3)
|
||
|
|
max_links=10, # Maximum number of links to follow (default: 10)
|
||
|
|
min_content_length=100, # Minimum content length to be considered valid
|
||
|
|
timeout=30, # Request timeout in seconds
|
||
|
|
max_retries=3, # Maximum retry attempts for failed requests
|
||
|
|
vector_db=vector_db # Vector database for storing extracted content
|
||
|
|
)
|
||
|
|
|
||
|
|
# Load knowledge base (crawl websites and store in vector DB)
|
||
|
|
kb.load(
|
||
|
|
recreate=False, # Whether to recreate the collection
|
||
|
|
upsert=True, # Whether to update existing documents
|
||
|
|
filters={"name": "example"} # Additional filters for the documents
|
||
|
|
)
|
||
|
|
```
|
||
|
|
|
||
|
|
### High-Performance Configuration with Optimized Vector Database
|
||
|
|
|
||
|
|
For maximum performance, use the `OptimizedPgVector` class with increased parallelism settings:
|
||
|
|
|
||
|
|
```python
|
||
|
|
from app.knowledge.enhanced_website_kb import EnhancedWebsiteKnowledgeBase
|
||
|
|
from app.knowledge.optimized_pgvector import OptimizedPgVector
|
||
|
|
|
||
|
|
# Initialize optimized vector database
|
||
|
|
vector_db = OptimizedPgVector(
|
||
|
|
table_name="your_table",
|
||
|
|
db_url="your_db_url",
|
||
|
|
schema="your_schema"
|
||
|
|
)
|
||
|
|
|
||
|
|
# Create knowledge base with increased parallelism
|
||
|
|
kb = EnhancedWebsiteKnowledgeBase(
|
||
|
|
urls=["https://example.com"],
|
||
|
|
max_depth=5, # Deeper crawling for more content
|
||
|
|
max_links=25, # More links for comprehensive coverage
|
||
|
|
min_content_length=100,
|
||
|
|
timeout=30,
|
||
|
|
max_retries=3,
|
||
|
|
max_workers=32, # High parallel processing for maximum throughput
|
||
|
|
batch_size=100, # Larger batch size for better database performance
|
||
|
|
vector_db=vector_db
|
||
|
|
)
|
||
|
|
|
||
|
|
# Load knowledge base
|
||
|
|
kb.load(
|
||
|
|
recreate=False,
|
||
|
|
upsert=True,
|
||
|
|
filters={"source": "website"}
|
||
|
|
)
|
||
|
|
```
|
||
|
|
|
||
|
|
## Performance Optimization
|
||
|
|
|
||
|
|
The system is designed to maximize performance at every stage:
|
||
|
|
|
||
|
|
1. **Parallel Crawling**: Multiple URLs are crawled simultaneously using ThreadPoolExecutor
|
||
|
|
2. **Parallel Embedding**: Documents from each URL are embedded in parallel batches
|
||
|
|
3. **Final Parallel Embedding**: Any remaining unembedded documents are processed with high parallelism
|
||
|
|
4. **Embedding Preservation**: The OptimizedPgVector class preserves embeddings during database operations
|
||
|
|
5. **Batched Database Operations**: Documents are inserted into the database in optimized batches
|
||
|
|
6. **Vector Database Indexing**: Automatic index optimization for faster vector searches
|
||
|
|
|
||
|
|
This approach dramatically reduces the total processing time, especially for large websites with many pages.
|
||
|
|
|
||
|
|
### Configuration Options
|
||
|
|
|
||
|
|
The `EnhancedWebsiteReader` and `EnhancedWebsiteKnowledgeBase` classes offer several configuration options:
|
||
|
|
|
||
|
|
- **max_depth**: How many levels deep to crawl from the starting URL (default: 5)
|
||
|
|
- **max_links**: Maximum number of links to follow (default: 25)
|
||
|
|
- **min_content_length**: Minimum text length to be considered valid content (default: 100)
|
||
|
|
- **timeout**: HTTP request timeout in seconds (default: 30)
|
||
|
|
- **max_retries**: Maximum number of retry attempts for failed requests (default: 3)
|
||
|
|
- **max_workers**: Number of parallel workers for crawling and embedding (default: 10)
|
||
|
|
- **crawl_scope**: How far link-following may wander from the starting URL (default: `host`)
|
||
|
|
- `host` — pages on the starting URL's own host only (`www.` and the bare host count as one host)
|
||
|
|
- `path` — that host, restricted to the starting URL's path prefix (e.g. only `/hc/…`)
|
||
|
|
- `domain` — every host on the registrable domain, so a `help.example.com` crawl also
|
||
|
|
walks `www.example.com`, `example.com/blog/…` and other subdomains
|
||
|
|
Only `http`/`https` links are ever followed — `mailto:`, `tel:` and friends are not pages.
|
||
|
|
|
||
|
|
Content stored by earlier, wider crawls is cleaned up in two steps:
|
||
|
|
|
||
|
|
- Pages that were never pages (mangled `https://mailto:a@example.com/…` URLs) are deleted
|
||
|
|
automatically by the `purge_mangled_crawl_pages_001` migration.
|
||
|
|
- Real pages that are simply outside the new scope (a marketing site pulled in from a
|
||
|
|
help-center seed) are left alone; `scripts/prune_offsite_pages.py` reports them per
|
||
|
|
source and deletes them only with `--apply`.
|
||
|
|
- **batch_size**: Size of document batches for database operations (default: 20)
|
||
|
|
- **blacklist_tags**: HTML tags to remove before content extraction (scripts, styles, etc.)
|
||
|
|
- **min_content_length**: Floor a page's extracted text must clear to count as readable (default: 100)
|
||
|
|
|
||
|
|
Candidate containers and the retention threshold live in `main_content.py`
|
||
|
|
(`CANDIDATE_TAGS`, `CONTENT_RETENTION`), shared with the help-center importer.
|
||
|
|
|
||
|
|
## Content Extraction Strategy
|
||
|
|
|
||
|
|
Selection happens in `main_content.select_main_node()`, shared with the help-center
|
||
|
|
article importer: it picks the **deepest container that still holds at least
|
||
|
|
`CONTENT_RETENTION` (90%) of the page's non-boilerplate text**, which resolves to
|
||
|
|
`<main>` or the content `<div>` where one exists and to `<body>` otherwise.
|
||
|
|
Navigation chrome (`nav`, `header`, `footer`, `aside`) is excluded when measuring,
|
||
|
|
so a page whose only text is a phone number and a login link reads as empty.
|
||
|
|
|
||
|
|
This replaced a walk that returned the *first* candidate clearing
|
||
|
|
`min_content_length`. That floor is not a quality bar — a hero banner clears it —
|
||
|
|
so a page whose first `<article>` was a 108-character search widget indexed the
|
||
|
|
widget and discarded 4,500 characters. Choosing by how much of the page a
|
||
|
|
container holds cannot make that mistake.
|
||
|
|
|
||
|
|
If the selected node yields less than `min_content_length`, the page is thin or
|
||
|
|
JavaScript-rendered and these fallbacks run in order:
|
||
|
|
|
||
|
|
1. **Density-based extraction**: Analyzes paragraph density to identify content-rich areas.
|
||
|
|
2. **Meaningful-element extraction**: Collects headings, paragraphs, lists and tables.
|
||
|
|
3. **Body fallback**: The cleaned body content.
|
||
|
|
4. **Last resort**: All text in the document.
|
||
|
|
|
||
|
|
Falling through to these is also what routes a JavaScript-rendered page to the
|
||
|
|
Crawl4AI browser fallback in `_process_url` — so boilerplate must never be
|
||
|
|
allowed to clear the floor on its own.
|
||
|
|
|
||
|
|
## Testing
|
||
|
|
|
||
|
|
The system includes comprehensive unit tests to ensure proper functionality:
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# Activate the Python environment
|
||
|
|
conda activate python3128
|
||
|
|
|
||
|
|
# Run the tests
|
||
|
|
python -m pytest backend/tests/knowledge/test_enhanced_website_reader.py -v
|
||
|
|
python -m pytest backend/tests/knowledge/test_enhanced_website_kb.py -v
|
||
|
|
python -m pytest backend/tests/knowledge/test_optimized_pgvector.py -v
|
||
|
|
```
|