Lightweight framework for AI-powered document analysis and search workflows with multi-provider support
Project description
AI Search Match Framework (ASMF)
Lightweight Python framework for building AI-powered search and analysis applications.
ASMF provides clean abstractions for common AI workflows: document parsing, AI provider management with automatic fallback, and extensible analysis patterns. Perfect for building domain-specific tools like patent analyzers, grant finders, or contract review systems.
Why ASMF?
The problem: Building AI apps requires boilerplate for provider management, document parsing, and analysis patterns.
The solution: ASMF gives you:
- 🤖 Multi-provider AI - Gemini + Ollama with automatic fallback
- 📄 Document parsing - PDF extraction with domain-specific parsers
- 🔧 Extensible analyzers - Base classes for custom analysis logic
- 🎯 Type-safe - Full type hints for IDE support
- ✅ Well-tested - 80%+ coverage, production-ready
Not a general LLM framework - LangChain and LlamaIndex are better for RAG/chatbots. ASMF is for linear search-analyze-evaluate workflows.
Quick Start
pip install ai-search-match-framework
from asmf.providers import AIProviderFactory
from asmf.parsers import PDFPatentParser
from asmf.analyzers import BaseAnalyzer
# 1. AI Provider with automatic fallback
provider = AIProviderFactory.create_provider() # Tries Gemini → Ollama
response = provider.analyze_text("Analyze this patent abstract...")
# 2. Document parsing
parser = PDFPatentParser()
patent = parser.parse("patent.pdf")
print(f"Claims: {len(patent.claims)}")
# 3. Custom analyzer
class PatentAnalyzer(BaseAnalyzer):
def analyze(self, patent_text):
prompt = f"Rate innovation: {patent_text}"
return {"score": self.provider.analyze_text(prompt)}
analyzer = PatentAnalyzer(provider)
results = analyzer.batch_analyze([doc1, doc2, doc3])
Core Components
AI Providers (asmf.providers)
Unified interface for AI models with automatic fallback:
GeminiProvider- Google Gemini APIOllamaProvider- Local OllamaAIProviderFactory- Automatic selection (Gemini → Ollama)
# Prefer local-first
provider = AIProviderFactory.create_provider(prefer_local=True)
Document Parsers (asmf.parsers)
Extract structured data from documents:
PDFPatentParser- Patent claims, abstracts, metadata- Extensible for custom formats
parExamples
**Patent Analysis:**
```python
from asmf.parsers import PDFPatentParser
from asmf.providers import GeminiProvider
parser = PDFPatentParser()
provider = GeminiProvider(api_key="...")
patent = parser.parse("us_patent.pdf")
for claim in patent.get_independent_claims():
analysis = provider.analyze_text(
f"Evaluate novelty: {claim.text}",
context={"title": patent.title}
)
print(analysis)
Grant Matching:
from asmf.analyzers import BaseAnalyzer
class GrantMatcher(BaseAnalyzer):
def __init__(self, provider, profile):
super().__init__(provider)
self.profile = profile
def analyze(self, grant_text):
prompt = f"Match grant to profile:\nGrant: {grant_text}\nProfile: {self.profile}"
score = self.provider.analyze_text(prompt)
return {"score": score, "grant": grant_text}
matcher = GrantMatcher(provider, profile="biotech research")
matches = matcher.batch_analyze(grant_descriptions)
See examples/job_finder/ for a complete application demonstrating multi-source aggregation and tracking.
Configuration
Environment Variables:
GEMINI_API_KEY=your_key_here
OLLAMA_BASE_URL=http://localhost:11434 # optional
OLLAMA_TIMEOUT=5.0 # optional
Provider Selection:
# Default: Gemini first, then Ollama
provider = AIProviderFactory.create_provider()
# Local-first
provider = AIProviderFactory.create_provider(prefer_local=True)
# Specific provider
provider = GeminiProvider(api_key="...", model="gemini-1.5-pro")
provider = OllamaProvider(model="qwen2.5-coder:32b")te", "value": "example.com"},
{"type": "employer", "value": "Bad Company"}
]
}
System Instructions
{
"system_instructions": "You are evaluating job leads for..."
}
Provider Settings
{
"providers": {
"linkedin": {"enabled": true, "max_results": 50},
"indeed": {"enabled": true, "max_results": 50}
}
}
Extensibility
Adding New Data Sources
- Implement
BaseProviderinterface - Add to
providers/directory - Register in aggregator
Adding New AI Providers
- Implement standard interface (rank_items, evaluate)
- Add to provider chain with fallback
- Configure in environment
Custom Evaluation Criteria
- Update system instructions
- Modify scoring prompts
- Adjust threshold values
Testing
Comprehensive test suite with:
- Unit tests for all components
- Integration tests for workflows
- Slow tests marked separately
- Fixtures for common test data
# Run fast tests
uv run pytest -m "not slow"
# Run all tests
uv run pytest
# Run specific component
uv run pytest tests/test_job_finder.py
Workflows
GitHub Actions
- CI/CD - Automated testing and validation
- Version Bump - Automatic versioning on merge
- Auto-Revert - Rollback on CI failure
- Branch Protection - Enforce PR workflow
Pre-commit Hooks
- Code formatting (black, isort)
- Linting (flake8)
- Security checks
- Test execution
Security
- No PII in repository (automated scans)
- API keys via environment variables only
- Input validation and sanitization
- Rate limiting on external APIs
- CORS protection on web endpoints
- Trusted PyPI publishing (no API tokens)
- Weekly vulnerability scans
Publishing
This framework is published to PyPI with automated workflows:
- Auto-tagging: Merges to
maincreate version tags - Auto-publishing: GitHub Releases trigger PyPI uploads
- Pre-publish tests: Full test suite runs before publishing
See docs/PUBLISHING.md for details.
Documentation
- docs/PUBLISHING.md - Release process
- docs/RELEASE_CHECKLIST.md - Pre-release checklist
- docs/CONFIGURATION.md - Configuration guide
- docs/PATTERNS.md - Usage patterns
.github/copilot-instructions.md- Development guidelines
License
MIT License - See LICENSE file for details
Contributing
- Follow
.github/copilot-instructions.mdguidelines - Use feature branches with descriptive names
- Include tests for new features (maintain 75%+ coverage)
- Update documentation for API changes
- Run pre-commit checks before pushing
Credits
Built with AI assistance using:
- GitHub Copilot (Claude Sonnet 4.5)
- Gemini 2.5 Flash
- Ollama (local models)
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file ai_search_match_framework-0.2.0.tar.gz.
File metadata
- Download URL: ai_search_match_framework-0.2.0.tar.gz
- Upload date:
- Size: 14.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e1f954be03ddc55b9ef0482408aad6beabede053ab70351402d636b4ce6f3d8d
|
|
| MD5 |
1f7b95e464d4acbe628f17f01246ea54
|
|
| BLAKE2b-256 |
226337d378a393750aaf97a593c7ef07baed9818686ad6514bb8a53f3c7b3a66
|
Provenance
The following attestation bundles were made for ai_search_match_framework-0.2.0.tar.gz:
Publisher:
publish.yml on vcaboara/ai-search-match-framework
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
ai_search_match_framework-0.2.0.tar.gz -
Subject digest:
e1f954be03ddc55b9ef0482408aad6beabede053ab70351402d636b4ce6f3d8d - Sigstore transparency entry: 763953557
- Sigstore integration time:
-
Permalink:
vcaboara/ai-search-match-framework@2feb2440223b745f6787e2ed853a481a315f47b8 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/vcaboara
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@2feb2440223b745f6787e2ed853a481a315f47b8 -
Trigger Event:
workflow_dispatch
-
Statement type:
File details
Details for the file ai_search_match_framework-0.2.0-py3-none-any.whl.
File metadata
- Download URL: ai_search_match_framework-0.2.0-py3-none-any.whl
- Upload date:
- Size: 14.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
539d2a7403a8804f365abbac76002726b48f9165772013389cc2f5a979b135e3
|
|
| MD5 |
49f78c9cb864d2b3699633591be31e13
|
|
| BLAKE2b-256 |
413fbedfd8cacc3c3ed63226ac648434e61b926a45d2c015f481a3d24b4f4532
|
Provenance
The following attestation bundles were made for ai_search_match_framework-0.2.0-py3-none-any.whl:
Publisher:
publish.yml on vcaboara/ai-search-match-framework
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
ai_search_match_framework-0.2.0-py3-none-any.whl -
Subject digest:
539d2a7403a8804f365abbac76002726b48f9165772013389cc2f5a979b135e3 - Sigstore transparency entry: 763953560
- Sigstore integration time:
-
Permalink:
vcaboara/ai-search-match-framework@2feb2440223b745f6787e2ed853a481a315f47b8 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/vcaboara
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@2feb2440223b745f6787e2ed853a481a315f47b8 -
Trigger Event:
workflow_dispatch
-
Statement type: