SummarizerApp / NDJSON_REFACTOR_SUMMARY.md
ming
feat: Add V4 NDJSON patch-based structured summarization
93c9664

NDJSON Refactor Summary

βœ… What Was Done

1. Refactored StructuredSummarizer Service

File: app/services/structured_summarizer.py

Added/Modified:

  • Updated _build_system_prompt(): Now instructs the model to output NDJSON patches instead of a single JSON object
  • Added _empty_state(): Creates the initial empty state structure
  • Added _apply_patch(): Applies NDJSON patches to the state (handles set, append, and done operations)
  • Added summarize_structured_stream_ndjson(): New async generator method that:
    • Uses deterministic decoding (do_sample=False, temperature=0.0)
    • Parses NDJSON line-by-line with buffering
    • Applies patches to build up state incrementally
    • Yields structured events with delta, state, done, tokens_used, and latency_ms
    • Handles errors gracefully

Preserved:

  • βœ… Class name: StructuredSummarizer
  • βœ… Logging style
  • βœ… Model loading/warmup logic
  • βœ… Settings usage
  • βœ… Existing summarize_structured_stream() method (unchanged)

2. Created New API Endpoint

File: app/api/v4/structured_summary.py

Added:

  • /api/v4/scrape-and-summarize/stream-ndjson endpoint
  • _stream_generator_ndjson() helper function
  • Supports both URL and text modes
  • Wraps NDJSON events in SSE format
  • Includes metadata events when requested

3. Created Test Suite

Test Files Created:

  1. test_v4_ndjson.py - Direct service test (requires model loaded)
  2. test_v4_ndjson_mock.py - Mock test without model (validates protocol logic) βœ… PASSED
  3. test_v4_ndjson_http.py - HTTP endpoint test (requires server running)

🎯 NDJSON Protocol Specification

Target Logical Object

{
  "title": "string",
  "main_summary": "string",
  "key_points": ["string"],
  "category": "string",
  "sentiment": "positive" | "negative" | "neutral",
  "read_time_min": number
}

Patch Operations

1. Set scalar field

{"op": "set", "field": "title", "value": "Example Title"}
{"op": "set", "field": "category", "value": "Tech"}
{"op": "set", "field": "sentiment", "value": "positive"}
{"op": "set", "field": "read_time_min", "value": 3}
{"op": "set", "field": "main_summary", "value": "Summary text..."}

2. Append to array

{"op": "append", "field": "key_points", "value": "First key point"}
{"op": "append", "field": "key_points", "value": "Second key point"}

3. Signal completion

{"op": "done"}

Event Structure

Each streamed event has this structure:

{
  "delta": {<patch>} | null,
  "state": {<current_combined_state>} | null,
  "done": boolean,
  "tokens_used": number,
  "latency_ms": number (optional, final event only),
  "error": "string" (optional, only on error)
}

πŸ§ͺ How to Test

Option 1: Mock Test (No Model Required) βœ… WORKING

python test_v4_ndjson_mock.py

Status: βœ… Passed all validations

  • Tests protocol logic
  • Validates state management
  • Shows expected event flow

Option 2: Direct Service Test (Requires Model)

python test_v4_ndjson.py

Requirements:

  • Model must be loaded in the environment
  • Transformers library installed

Option 3: HTTP Endpoint Test (Requires Running Server)

# Terminal 1: Start server
./start-server.sh

# Terminal 2: Run test
python test_v4_ndjson_http.py

πŸ“Š Test Results

Mock Test Results βœ…

Total events: 12
Total tokens: 55

Final State:
{
  "title": "Qwen2.5-0.5B: Efficient AI for Edge Computing",
  "main_summary": "Qwen2.5-0.5B is a compact language model...",
  "key_points": [
    "Compact 0.5B parameter model designed for edge devices...",
    "Strong performance on instruction following...",
    "Supports multiple languages...",
    "Significantly lower memory and computational requirements...",
    "Ideal for applications requiring efficiency and low latency"
  ],
  "category": "Tech",
  "sentiment": "positive",
  "read_time_min": 3
}

Validations:
βœ… title: present
βœ… main_summary: present
βœ… key_points: 5 items
βœ… category: present
βœ… sentiment: valid value (positive)
βœ… read_time_min: present

βœ… ALL VALIDATIONS PASSED - Protocol is working correctly!

πŸ”„ Migration Path

Current State

  • βœ… Old method still works: summarize_structured_stream()
  • βœ… New method available: summarize_structured_stream_ndjson()
  • βœ… Old endpoint still works: /api/v4/scrape-and-summarize/stream
  • βœ… New endpoint available: /api/v4/scrape-and-summarize/stream-ndjson

When Ready to Switch

  1. Update your frontend/client to use the new endpoint
  2. Consume events using the new structure:
    // Parse SSE event
    const event = JSON.parse(eventData);
    
    // Use current full state
    const currentState = event.state;
    
    // Or use delta for fine-grained updates
    const patch = event.delta;
    
    // Check completion
    if (event.done) {
      console.log('Final latency:', event.latency_ms);
    }
    
  3. Once migrated, you can optionally remove the old method (or keep both)

πŸŽ‰ Benefits of NDJSON Protocol

  1. Incremental State Updates: Client sees partial results as they're generated
  2. Fine-Grained Control: Can update UI field-by-field
  3. Deterministic: Uses greedy decoding for consistent results
  4. Structured Events: Clear separation of deltas and state
  5. Error Handling: Graceful error reporting with proper event structure
  6. Backwards Compatible: Old endpoint continues to work

πŸ“ Next Steps

  1. βœ… Protocol logic verified - Mock test passed
  2. ⏳ Test with actual model - Run when model is loaded
  3. ⏳ Test HTTP endpoint - Run when server is up
  4. ⏳ Update frontend - Integrate new endpoint in client
  5. ⏳ Monitor production - Compare performance with old method

πŸ› Troubleshooting

Model not loaded

❌ ERROR: Model not available. Please check model initialization.

Solution: Make sure transformers and torch are installed and model files are available.

Server not running

❌ Could not connect to server at http://localhost:7860

Solution: Start the server with ./start-server.sh

Invalid JSON in stream

If the model outputs invalid JSON, it will be logged as a warning and skipped:

Failed to parse NDJSON line: {...}... Error: ...

Solution: This is handled gracefully - other valid patches will still be processed.


πŸ“š Files Modified/Created

Modified:

  • app/services/structured_summarizer.py - Added NDJSON streaming method
  • app/api/v4/structured_summary.py - Added new endpoint

Created:

  • test_v4_ndjson.py - Direct service test
  • test_v4_ndjson_mock.py - Mock test βœ…
  • test_v4_ndjson_http.py - HTTP endpoint test
  • NDJSON_REFACTOR_SUMMARY.md - This file

Status: βœ… Refactor complete and protocol validated Ready for: Model testing and integration