Skip to content

Latest commit

Β 

History

13 Commits

Folders and files

NameName
Last commit message
Last commit date
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

ACUITY Framework

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).


πŸš€ Installation

# 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]

Local Development Install

git clone https://github.com/acuity-framework/acuity-framework.git
cd acuity-framework
pip install -e ".[dev]"

πŸ“¦ Modules

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)

πŸ”§ Quick Start

1. Extract Business Profiles from Text

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']}")

2. Verify Against a Government Registry

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.65

3. Recommend Businesses

from 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")

πŸ”Œ Extensibility (v3.0)

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.

Custom NER Backend

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"])

Custom Data Source

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"])

Custom Ranking Strategy

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.


βš™οΈ Configuration

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,
)

🌐 Integrating with Your Web Application

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.


πŸ§ͺ Running Tests

pip install -e ".[dev]"
pytest tests/ -v

πŸ“ Project Structure

acuity-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

πŸ“„ License

MIT License β€” see LICENSE for details.


πŸŽ“ Academic Reference

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

About

A Python ML framework for extracting, verifying, and recommending local micro-enterprises from unstructured social media community posts.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages