Spaces:
Sleeping
Sleeping
| # 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 | |
| ```json | |
| { | |
| "title": "string", | |
| "main_summary": "string", | |
| "key_points": ["string"], | |
| "category": "string", | |
| "sentiment": "positive" | "negative" | "neutral", | |
| "read_time_min": number | |
| } | |
| ``` | |
| ### Patch Operations | |
| #### 1. Set scalar field | |
| ```json | |
| {"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 | |
| ```json | |
| {"op": "append", "field": "key_points", "value": "First key point"} | |
| {"op": "append", "field": "key_points", "value": "Second key point"} | |
| ``` | |
| #### 3. Signal completion | |
| ```json | |
| {"op": "done"} | |
| ``` | |
| ### Event Structure | |
| Each streamed event has this structure: | |
| ```json | |
| { | |
| "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 | |
| ```bash | |
| 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) | |
| ```bash | |
| python test_v4_ndjson.py | |
| ``` | |
| **Requirements:** | |
| - Model must be loaded in the environment | |
| - Transformers library installed | |
| ### Option 3: HTTP Endpoint Test (Requires Running Server) | |
| ```bash | |
| # 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: | |
| ```javascript | |
| // 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 | |