TextGuard: Building a Spam Detection App

I built a spam detector without using any AI APIs. Here's how heuristics and basic probability can go a long way.

The Project

TextGuard is a spam detection demo I built to explore what's possible without reaching for an LLM.

The idea: can we build something useful with just pattern matching and basic statistics?

The Approach

Heuristics

Some signals are obvious spam indicators:

function getHeuristicScore(text) {
  let score = 0;
  
  // Excessive caps
  const capsRatio = (text.match(/[A-Z]/g) || []).length / text.length;
  if (capsRatio > 0.5) score += 0.2;
  
  // Too many exclamation marks
  const exclamations = (text.match(/!/g) || []).length;
  if (exclamations > 3) score += 0.15;
  
  // Contains suspicious URLs
  if (text.match(/bit\.ly|tinyurl|click here/i)) score += 0.3;
  
  // Money/urgency language
  if (text.match(/free|winner|urgent|limited time/i)) score += 0.2;
  
  return Math.min(score, 1);
}

Naive Bayes

For the probabilistic part, I used a simple Naive Bayes classifier trained on labeled examples:

class NaiveBayes {
  constructor() {
    this.wordCounts = { spam: {}, ham: {} };
    this.categoryCounts = { spam: 0, ham: 0 };
  }
  
  train(text, category) {
    const words = this.tokenize(text);
    words.forEach(word => {
      this.wordCounts[category][word] = 
        (this.wordCounts[category][word] || 0) + 1;
    });
    this.categoryCounts[category]++;
  }
  
  classify(text) {
    const words = this.tokenize(text);
    
    let spamScore = Math.log(this.categoryCounts.spam / this.totalDocs());
    let hamScore = Math.log(this.categoryCounts.ham / this.totalDocs());
    
    words.forEach(word => {
      spamScore += Math.log(this.wordProbability(word, 'spam'));
      hamScore += Math.log(this.wordProbability(word, 'ham'));
    });
    
    return spamScore > hamScore ? 'spam' : 'ham';
  }
}

Combining Scores

The final score is a weighted combination:

function getSpamScore(text) {
  const heuristicScore = getHeuristicScore(text);
  const bayesScore = classifier.getScore(text);
  
  return (heuristicScore * 0.3) + (bayesScore * 0.7);
}

The Stack

  • **Frontend**: React with Vite
  • **Backend**: Express.js
  • **No database** - Classifier trained at startup from JSON file

What I Learned

1. **Simple often works** - You don't need GPT-4 for everything 2. **Heuristics are underrated** - Domain knowledge beats algorithms 3. **Probability basics go far** - Naive Bayes is surprisingly effective

Try It

What simple approaches have you used instead of reaching for ML/AI?

Back to Journal