defraudai.opscores.in
DeFraudAI

DeFraudAI

A misinformation-fighting platform: CNN deepfake detection, Gemini text credibility analysis, and a browser extension - all served at the edge.

Timeline
2023 - 24
Role
ML + full-stack
Team
Solo
Status
shipped

Technology Stack

ReactReactViteVitePythonPythonTensorFlowTensorFlowFlaskFlaskHonoHonoCloudflare WorkersCloudflare WorkersGemini AIGemini AIThree.jsThree.js

Overview

DeFraudAI is a misinformation-fighting platform with two detection surfaces: a TensorFlow CNN that classifies images as real or deepfake (92% accuracy), and a Gemini-powered text credibility analyser that scores articles and claims on a 0–1 trust scale with keyword flagging and source cross-referencing. Both surfaces are accessible from a browser extension without leaving the page.

The architecture is split across three runtimes deliberately: Python/Flask hosts TensorFlow model inference (224×224 pixel normalisation, MobileNet transfer learning); Hono on Cloudflare Workers caches text analysis results in D1 SQLite so identical content skips the Gemini API call entirely; and the React + Three.js frontend presents trust data as a spatial 3D interface rather than a flat dashboard.

Key Features

  • TensorFlow deepfake detection (92%) - A CNN trained with MobileNet transfer learning classifies uploaded images as real or deepfake with a confidence score. Input images are resized to 224×224, normalised to [0,1], and run through the model in a Flask API.

  • Gemini text credibility analysis - News articles, social posts and claims are scored on a 0-1 trust scale with keyword flagging. Results are cached by SHA-256 content hash on Cloudflare D1 - the same viral article is analysed once, then served from cache.

  • Browser extension (Manifest V3) - A Chrome extension injects an analysis button on any page. Selected text or the current URL is sent for fact-checking inline - no tab-switching. Built with Manifest V3's service-worker model; results stored in chrome.storage.local.

  • Hono on Cloudflare Workers + D1 - Text analysis routes globally on Cloudflare's edge network, co-located with D1 SQLite for cache lookups. Identical content hashes skip Gemini entirely - cost is amortised across every submission of the same content.

  • Three.js 3D trust visualisation - @react-three/fiber renders deepfake confidence and trust scores as a spatial 3D interface - not a flat table. Trust data has a sense of depth: high-confidence real content feels distinct from borderline cases.

Technical Implementation

01TF model inference - deepfake_detection.py

The saved Keras model (trained with MobileNet transfer learning) is loaded once at Flask startup. Per-request inference: PIL decodes the uploaded image, resizes to 224x224, normalises pixels to [0,1], adds the batch dimension and calls model.predict. The scalar output maps directly to confidence - above 0.5 is deepfake.

deepfake_detection.py
python
def predict_deepfake(image_data: bytes) -> dict:
    # Decode, resize to model input, normalise to [0, 1]
    img = Image.open(io.BytesIO(image_data)).resize((224, 224))
    img_array = np.array(img) / 255.0
    img_array = np.expand_dims(img_array, axis=0)   # add batch dim

    prediction = model.predict(img_array)[0][0]
    return {
        "is_deepfake": bool(prediction > 0.5),
        "confidence": float(prediction),  # 0 = real, 1 = deepfake
    }

02Cloudflare Worker - content hash cache

Identical content should never call Gemini twice. The worker hashes the lowercased, trimmed content with Web Crypto SHA-256, queries D1 for a cached result, and proceeds to Gemini only on a miss. The result is stored immediately after, so every subsequent submission is instant.

src/worker/index.ts
ts
app.post('/api/analyze', zValidator('json', AnalysisRequestSchema), async (c) => {
  const { content } = c.req.valid('json');

  // Deterministic hash - same content always maps to the same cache key
  const data = new TextEncoder().encode(content.toLowerCase().trim());
  const hash = await crypto.subtle.digest('SHA-256', data);
  const contentHash = [...new Uint8Array(hash)]
    .map(b => b.toString(16).padStart(2, '0')).join('');

  // D1 cache lookup - skip Gemini on repeat submissions
  const cached = await c.env.DB.prepare(
    'SELECT * FROM analysis_results WHERE content_hash = ? LIMIT 1'
  ).bind(contentHash).first();
  if (cached) return c.json(JSON.parse(String(cached.result)));

  const result = await analyzeContent(content);   // → Gemini API
  await c.env.DB.prepare(
    'INSERT INTO analysis_results (content_hash, ...) VALUES (?, ...)'
  ).bind(contentHash /*, ... */).run();
  return c.json(result);
});

03D1 schema - analysis cache

A single table stores the hash, content, trust score, status, flags and source list. The schema is minimal - all heavy processing happens in the Worker function, not in SQL. The content_hash primary key makes lookups O(1).

ColumnTypePurpose
content_hashTEXT PKSHA-256 of normalised input - cache key
trust_scoreREAL0–1 confidence (1 = fully trustworthy)
statusTEXTverified / suspicious / unknown
keywordsJSONFlagged terms extracted by Gemini
sourcesJSONCross-referenced source URLs
created_atDATETIMECache entry timestamp

Project Structure

structure
defraudai/
├─ src/
│  ├─ react-app/      # React + Three.js frontend
│  │  └─ pages/       # Landing, DeepFactAnalysis, SourceIntelligence…
│  ├─ worker/         # Hono on Cloudflare Workers (content cache + routing)
│  └─ shared/         # Zod schemas, shared types
├─ browser-extension/ # Manifest V3 — inline page analysis
│  ├─ content.js      # injects analysis button on every page
│  └─ popup.js        # results view
└─ DefraudAi-backend-repo/
   ├─ app.py          # Flask API — /api/detect-deepfake
   ├─ deepfake_detection.py  # TF inference (224×224, MobileNet)
   └─ train_model.py  # transfer learning training script

Design Decisions

Three separate runtimes, deliberately

Python/Flask for ML inference (TensorFlow is Python-native and the ecosystem doesn't work anywhere else cleanly), Hono/Workers for global edge caching (Cloudflare D1 is co-located with Workers, not a network call away), React for the interactive frontend. Each runtime does what it's best at.

Content hashing before Gemini

Viral misinformation repeats. The same debunked claim will be submitted thousands of times. Caching by SHA-256 hash means the Gemini API cost is paid once per unique piece of content - every submission after the first is free and instant from D1.

Challenges

Model accuracy on compressed social media images

Social images are JPEG-compressed multiple times before they reach users. Compression artefacts invisible to humans can fool a CNN trained on clean data. Mitigated by augmenting training data with compression noise and normalising JPEG quality before inference.

Manifest V3 service-worker constraints

Manifest V3 replaced persistent background pages with short-lived service workers - the extension can't maintain an open connection. Deepfake analysis results are stored in chrome.storage.local so the popup can display them after the service worker has been terminated.

Want the full walkthrough - architecture, decisions, war stories?

ask me about it