Automated Community Unstructured Information to Targeted visibilitY
A Python machine learning framework for extracting, verifying, and recommending local micro-enterprise profiles from unstructured community posts (e.g., Facebook groups, forums).
# Core framework (no heavy dependencies)
pip install acuity-framework
# With NLP support (nltk for CRF-based NER)
pip install acuity-framework[nlp]
# With Transformer NER (requires PyTorch)
pip install acuity-framework[transformers]
# With Facebook scraper
pip install acuity-framework[scraper]
# Everything
pip install acuity-framework[all]git clone https://github.com/acuity-framework/acuity-framework.git
cd acuity-framework
pip install -e ".[dev]"| Module | Description |
|---|---|
acuity.extraction |
NLP pipeline: preprocessing β NER β rule-based extraction β profile construction |
acuity.recommendation |
TF-IDF + cosine similarity + Haversine proximity ranking |
acuity.verification |
Business legitimacy verification via fuzzy matching (Levenshtein) |
acuity.scraper |
Facebook community group post scraper (optional) |
from acuity.extraction import ExtractionPipeline
pipeline = ExtractionPipeline()
profiles = pipeline.extract_from_texts([
"Mang Juan's Bakery sa Mamatid, open 8am-5pm, 0917-123-4567, pandesal β±5",
"JC Auto Repair, vulcanizing, Brgy Banay-Banay, 0918-987-6543",
])
for p in profiles:
print(f"{p['business_name']}: {p['phones']}, {p['hours']}")from acuity.verification import BPLOVerifier
verifier = BPLOVerifier()
verifier.load_registry_from_list([
{"name": "Juan's Bakeshop", "address": "Mamatid"},
{"name": "JC Automotive Repair", "address": "Banay-Banay"},
])
result = verifier.verify("Mang Juan's Bakery")
print(f"Status: {result['status']}, Score: {result['score']}")
# Output: Status: Pending Verification, Score: 0.65from acuity.recommendation import RecommendationEngine
engine = RecommendationEngine()
engine.set_profiles([
{"name": "Juan's Bakery", "description": "Fresh bread daily", "latitude": 14.27, "longitude": 121.12},
{"name": "Auto Repair", "description": "Vulcanizing and oil change", "latitude": 14.26, "longitude": 121.11},
])
results = engine.recommend("bakery bread", user_lat=14.27, user_lon=121.12)
for r in results:
print(f"{r['name']}: score={r['final_score']}, dist={r['distance_km']}km")ACUITY v3.0 introduces three pluggable extension points via abstract base classes. You can inject custom implementations without modifying the framework's source code. All extension points are optional β existing code continues to work unchanged.
Replace the built-in CRF/Transformer NER with your own implementation:
from acuity.extraction.interfaces import NERBackend
from acuity.extraction import ExtractionPipeline
class MyNERBackend(NERBackend):
def extract_entities(self, text: str) -> dict:
# Your custom entity extraction logic
return {
"business_name": ["Detected Name"],
"categories": ["food"],
"locations": ["Manila"],
}
# Inject it β existing config-based NER is used when ner_backend=None (default)
pipeline = ExtractionPipeline(ner_backend=MyNERBackend())
profiles = pipeline.extract_from_texts(["Sample post text"])Replace the Facebook scraper with any data source (CSV, database, API, etc.):
from acuity.scraper.interfaces import DataSource
from acuity.extraction import ExtractionPipeline
class MyDataSource(DataSource):
def fetch_posts(self, sources: list[str], max_posts: int = 500) -> list[dict]:
# Your custom data fetching logic
return [{"text": "Post content", "poster": "Author Name"}]
# Inject it and use extract_from_source() for fetch + extract in one call
pipeline = ExtractionPipeline(data_source=MyDataSource())
profiles = pipeline.extract_from_source(sources=["my_source_id"])Replace TF-IDF + cosine similarity with your own text-relevance scoring:
from acuity.recommendation.interfaces import RankingStrategy
from acuity.recommendation import RecommendationEngine
class MyRanking(RankingStrategy):
def compute_scores(self, profiles: list[dict], query: str) -> list[float]:
# Your custom relevance scoring logic
return [1.0 if query.lower() in str(p).lower() else 0.0 for p in profiles]
# Inject it β Haversine proximity is still used alongside (it's a fixed formula)
engine = RecommendationEngine(ranking_strategy=MyRanking())
engine.set_profiles(profiles)
results = engine.recommend("bakery")Note: Haversine distance, the pipeline stage order (preprocess β NER β rules β postprocess), and Levenshtein fuzzy matching are intentionally not abstracted β they are fixed, correct algorithms with no legitimate variation.
See examples/demo_extensibility.py for a complete end-to-end demo using all three extension points.
All settings are controlled via the AcuityConfig dataclass:
from acuity.config import AcuityConfig
config = AcuityConfig(
# NER settings
ner_backend="crf", # "crf" or "transformer"
ner_model_path="./models/crf.pkl", # Path to your trained model
# Recommendation weights
relevance_weight=0.6,
proximity_weight=0.4,
default_top_k=10,
# Verification thresholds
fuzzy_match_threshold_verified=0.8,
fuzzy_match_threshold_pending=0.6,
)ACUITY is framework-agnostic. Here's how to use it with Flask:
from flask import Flask, request, jsonify
from acuity.recommendation import RecommendationEngine
app = Flask(__name__)
engine = RecommendationEngine()
@app.route("/api/recommend")
def recommend():
query = request.args.get("q", "")
results = engine.recommend(query)
return jsonify(results)See examples/flask_integration.py for a complete working example.
pip install -e ".[dev]"
pytest tests/ -vacuity-framework/
βββ pyproject.toml # Package configuration
βββ README.md
βββ LICENSE
βββ acuity/
β βββ __init__.py # Public API
β βββ config.py # AcuityConfig dataclass
β βββ utils.py # Levenshtein similarity utilities
β βββ extraction/ # NLP extraction pipeline
β β βββ pipeline.py # ExtractionPipeline class
β β βββ interfaces.py # NERBackend ABC (extensibility)
β β βββ preprocessing.py
β β βββ ner_crf.py
β β βββ ner_transformer.py
β β βββ rules.py
β β βββ postprocessing.py
β βββ recommendation/ # Recommendation engine
β β βββ engine.py # RecommendationEngine class
β β βββ interfaces.py # RankingStrategy ABC (extensibility)
β β βββ vectorizer.py # TF-IDF vectorizer
β β βββ similarity.py # Cosine similarity
β β βββ proximity.py # Haversine distance (fixed, not abstracted)
β β βββ ranker.py # Combined ranking
β βββ verification/ # Business verification
β β βββ bplo.py # BPLOVerifier class
β βββ scraper/ # Data collection (optional)
β βββ scraper.py # FacebookScraper class
β βββ interfaces.py # DataSource ABC (extensibility)
β βββ utils.py
βββ examples/
β βββ basic_extraction.py
β βββ basic_recommendation.py
β βββ flask_integration.py
β βββ custom_ner_backend.py # Example: KeywordNERBackend
β βββ custom_data_source.py # Example: CSVDataSource
β βββ custom_ranking_strategy.py # Example: KeywordMatchRanking
β βββ demo_extensibility.py # Combined end-to-end demo
βββ tests/
βββ test_extraction.py
βββ test_recommendation.py
βββ test_verification.py
MIT License β see LICENSE for details.
This framework was developed as part of an academic thesis at the College of Computing Studies. The core algorithms implement:
- TF-IDF Vectorization with log-normalised term frequency and inverse document frequency
- Cosine Similarity for textual relevance scoring
- Haversine Formula for geographic proximity computation
- CRF (Conditional Random Field) for Named Entity Recognition with BIO tagging
- Levenshtein Distance for fuzzy string matching in business verification