Ask The Game, the Build Log

The JSON Body Architecture: Why I Ditched Direct Database Inserts

What's broken about my first AI audio pipeline? I took raw transcription data and shoved it directly into a database. No structure, no validation, no thought about what happens downstream.

This approach was ... not great.

I built a JSON body architecture that transforms the way audio pipeline data flows from transcription to storage to retrieval.

The JSON Body Architecture

Instead of raw database inserts, every piece of audio data now flows through a structured JSON representation. Think of it as a contract between your transcription service and your database, with objective, enforced standards.

Here's what this architecture actually looks like:

Core Structure

{
  "episode_id": "9d6fc8f4-8519-4b78-bdfe-5de4af077736",
  "metadata": {
    "title": "How I Made Millions Without Being the Best - Part 1",
    "duration": 3420.5,
    "processed_at": "2025-06-27T21:34:06Z",
    "version": "v1.2"
  },
  "speakers": [
    {
      "id": "spk_001", 
      "name": "Alex Hormozi",
      "type": "host",
      "confidence": 0.94,
      "utterance_count": 351
    },
    {
      "id": "spk_002", 
      "name": "Guest_1",
      "type": "guest", 
      "confidence": 0.87,
      "utterance_count": 49
    }
  ],
  "chunks": [
    {
      "chunk_id": "c1",
      "text": "The key to building wealth isn't intelligence...",
      "start_time": 12.4,
      "end_time": 58.2,
      "speaker_id": "spk_001",
      "confidence": 0.96,
      "word_count": 47,
      "sentiment": "neutral",
      "sentiment_score": 0.12,
      "embedding": [0.1234, -0.5678, ...],
      "content_hash": "a1b2c3d4e5f6...",
      "processing_flags": {
        "confidence_filtered": true,
        "speaker_verified": true,
        "min_words_met": true
      }
    }
  ],
  "quality_metrics": {
    "total_utterances": 471,
    "chunks_created": 425,
    "confidence_pass_rate": 0.902,
    "average_confidence": 0.887,
    "speaker_switches": 84,
    "flagged_segments": 46,
    "dropped_segments": 0
  }
}

The ID-Based Relational System

Instead of hoping speaker names stay consistent, I built a proper relational system:

Speaker IDs: Every speaker gets a unique identifier (spk_001, spk_002) that persists throughout the episode. No more confusion when someone says "Alex" vs "Alexander" vs just getting their name wrong entirely.

Chunk References: Every text chunk references its speaker by ID, not name. This means I can update speaker information without having to touch thousands of chunk records.

Content Hashing: Each chunk gets a SHA-256 hash of its content. Duplicate detection, data integrity verification, and change tracking all become trivial.

The Processing Pipeline Flow

Here's how data actually flows through this architecture:

  1. Raw Transcription: Audio gets transcribed with timestamps and basic speaker detection
  2. JSON Structuring: Raw data gets transformed into my JSON schema with proper IDs and metadata
  3. Quality Filtering: Confidence filtering, min-words logic, and speaker verification happen at the JSON level
  4. Enrichment: Sentiment analysis, embeddings, and content hashing get added to the JSON
  5. Database Storage: Only clean, validated, structured data makes it to the database

Why Every Field Matters

Processing Flags: Each chunk contains metadata about the processing it underwent. Did it pass confidence filtering? Was the speaker verified? Did it meet minimum word requirements? This makes debugging and quality analysis possible.

Quality Metrics: The episode-level metrics aren't just nice-to-have. They're essential for understanding what your filtering is actually doing to your data. Are you throwing away too much? Not enough? The metrics tell you.

Version Tracking: The schema version field allows me to evolve my data structure without breaking existing processing. Critical for a system that's constantly improving.

Confidence Filtering in Practice

Based on my understanding so far, this is where the JSON architecture truly excels. Instead of making filtering decisions in the database layer, I handle them in the structured data layer:

"processing_config": {
  "confidence_threshold": 0.7,
  "min_words_default": 3,
  "min_words_high_confidence": {
    "90_percent": 2,
    "95_percent": 1
  },
  "preserve_short_responses": true
}

The system automatically applies these rules during JSON processing, and every decision gets logged in the processing flags. There's no black box filtering, so I can see exactly what happens to every piece of data.

Real-World Performance

This architecture handles real episodes with genuine complexity. For example, this episode featuring Alex Hormozi, interviewed by two people.

The Database Layer

Once data reaches the database, it's clean and structured. No more "fixing data at query time" because the data is already fixed:

-- This query works reliably because speaker_id is always valid
SELECT chunk_text, start_time, end_time 
FROM chunks 
WHERE speaker_id = 'spk_001' 
  AND confidence > 0.9
  ORDER BY start_time;

Error Handling and Recovery

The JSON architecture makes error recovery much simpler. If something breaks during database insertion, I still have the complete processed JSON. I can replay just the database insertion without re-running transcription, speaker detection, or confidence filtering.

The old way used up a lot of my Deepgram credits, and my laptop was struggling under the strain. But now, it's a bit better. ;)

Additionally, the content hashes enable me to detect and skip data that has already been processed, even across different pipeline runs.

Why This Matters for AI Applications

When my future chatbot answers "What does Alex Hormozi say about pricing?", the response quality depends entirely on data quality. With this JSON architecture:

It's not just about cleaner code, it's the difference between a chatbot that spits out random quotes and one I can really rely on.

Over-enginnering?

I wasn't aware of the advantages of JSON body architecture. It seemed like over-engineering until I remembered trying to debug why Claude Code or Gemini was attributing quotes incorrectly or why the confidence filtering was too aggressive.

I quickly realised that having a structured, validated, auditable data pipeline isn't complexity for its own sake. It's the foundation that makes everything else possible.

And honestly? It feels like vibe-coding with this new architecture feels a lot faster, a lot less complicated.

– Benoit Meunier