Date: Dec 9, 2025
Status: 🔍 ISSUE IDENTIFIED
Single blog test passed with HTML generation (38,180 chars), but all enhanced data fields are empty:
{
"citations": [],
"citations_count": 0,
"internal_links": [],
"internal_links_count": 0,
"toc": {},
"faq": [],
"faq_count": 0,
"paa": [],
"paa_count": 0,
"image_url": "",
"image_alt_text": "",
"image_prompt": "",
"publication_date": ""
}BUT the HTML content itself contains:
- ✅ 7 Citations in schema markup
- ✅ 6 FAQ items
- ✅ 3 PAA items
- ✅ Internal links to
/magazine/ - ✅ Images in HTML
This means the data EXISTS but is NOT being extracted correctly.
File: scripts/generate-blog.py (lines 304-390)
The script extracts data from context.parallel_results, but is using incorrect key names:
# CURRENT CODE (WRONG KEYS)
citations_data = parallel_results.get('citations', {})
if 'citation_list' in citations_data: # ❌ WRONG KEY
citations = citations_data['citation_list']
internal_links_data = parallel_results.get('internal_links', {})
if 'links' in internal_links_data: # ❌ WRONG KEY
internal_links = internal_links_data['links']Stage 4 (Citations): Stores data in context.parallel_results:
context.parallel_results["citations_html"] = html # ✅ Correct
context.parallel_results["citations_count"] = citation_list.count() # ✅ Correct
context.parallel_results["citations_list"] = citation_list # ⚠️ Should be thisStage 5 (Internal Links): Stores data in:
context.parallel_results["internal_links_html"] = html # ✅ Correct
context.parallel_results["internal_links_count"] = len(links) # ✅ Correct
context.parallel_results["internal_links_list"] = link_list # ⚠️ Should be thisStage 8 (FAQ/PAA): Stores data in:
context.parallel_results["faq_items"] = faq_list # ✅ Correct
context.parallel_results["paa_items"] = paa_list # ✅ Correct| Stage | Expected Key | Actual Key Used | Status |
|---|---|---|---|
| Citations | citations_list |
citation_list |
❌ Wrong |
| Internal Links | internal_links_list |
links |
❌ Wrong |
| FAQ | faq_items |
faq_items |
✅ Correct |
| PAA | paa_items |
paa_items |
✅ Correct |
| TOC | toc / toc_dict |
toc |
|
| Images | image_url, image_alt_text |
Same |
File: scripts/generate-blog.py
# BEFORE
citations_data = parallel_results.get('citations', {})
citations = []
if isinstance(citations_data, dict):
citations_html = citations_data.get('citations_html', '')
if 'citation_list' in citations_data: # ❌ WRONG
citations = citations_data['citation_list']
# AFTER
citations_data = parallel_results.get('citations', {})
citations = []
if isinstance(citations_data, dict):
# Try to get citations_list (Pydantic object)
citations_list_obj = citations_data.get('citations_list')
if citations_list_obj:
# Check if it's a Pydantic model with to_dict_list method
if hasattr(citations_list_obj, 'to_dict_list'):
citations = citations_list_obj.to_dict_list()
elif hasattr(citations_list_obj, 'citations'):
citations = citations_list_obj.citations
elif isinstance(citations_list_obj, list):
citations = citations_list_obj# BEFORE
internal_links_data = parallel_results.get('internal_links', {})
internal_links = []
if isinstance(internal_links_data, dict):
internal_links_html = internal_links_data.get('internal_links_html', '')
if 'links' in internal_links_data: # ❌ WRONG
internal_links = internal_links_data['links']
# AFTER
internal_links_data = parallel_results.get('internal_links', {})
internal_links = []
if isinstance(internal_links_data, dict):
# Try to get internal_links_list (Pydantic object)
links_list_obj = internal_links_data.get('internal_links_list')
if links_list_obj:
# Check if it's a Pydantic model with to_dict_list method
if hasattr(links_list_obj, 'to_dict_list'):
internal_links = links_list_obj.to_dict_list()
elif hasattr(links_list_obj, 'links'):
internal_links = links_list_obj.links
elif isinstance(links_list_obj, list):
internal_links = links_list_obj# CURRENT (should work but may need Pydantic handling)
faq_paa_data = parallel_results.get('faq_paa', {})
faq_items = []
paa_items = []
if isinstance(faq_paa_data, dict):
faq_items_obj = faq_paa_data.get('faq_items', [])
paa_items_obj = faq_paa_data.get('paa_items', [])
# Handle Pydantic objects
if hasattr(faq_items_obj, 'to_dict_list'):
faq_items = faq_items_obj.to_dict_list()
elif isinstance(faq_items_obj, list):
faq_items = faq_items_obj
if hasattr(paa_items_obj, 'to_dict_list'):
paa_items = paa_items_obj.to_dict_list()
elif isinstance(paa_items_obj, list):
paa_items = paa_items_obj# CURRENT
toc_data = parallel_results.get('toc', {})
toc = toc_data if isinstance(toc_data, dict) else {}
# SHOULD BE (check for toc_dict key)
toc_data = parallel_results.get('toc', {})
if isinstance(toc_data, dict):
# Try toc_dict first, fallback to toc itself
toc = toc_data.get('toc_dict', toc_data)
else:
toc = {}# CURRENT (may be missing data)
image_data = parallel_results.get('image', {})
image_url = ''
image_alt_text = ''
image_prompt = ''
if isinstance(image_data, dict):
image_url = image_data.get('image_url', '')
image_alt_text = image_data.get('image_alt_text', '')
image_prompt = image_data.get('image_prompt', '')
# ENHANCED (handle multiple possible keys)
image_data = parallel_results.get('image', {})
image_url = image_data.get('image_url') or image_data.get('url', '')
image_alt_text = image_data.get('image_alt_text') or image_data.get('alt_text', '')
image_prompt = image_data.get('image_prompt') or image_data.get('prompt', '')# CURRENT
metadata_extra = parallel_results.get('metadata', {})
publication_date = ''
if isinstance(metadata_extra, dict):
publication_date = metadata_extra.get('publication_date', '')
# ENHANCED (check multiple sources)
publication_date = ''
metadata_extra = parallel_results.get('metadata', {})
if isinstance(metadata_extra, dict):
publication_date = metadata_extra.get('publication_date', '')
# Fallback to context attributes
if not publication_date and hasattr(context, 'publication_date'):
publication_date = context.publication_dateAfter applying fixes:
- Run single blog test to verify enhanced data extraction
- Check output JSON for non-empty arrays:
citations_count> 0internal_links_count> 0faq_count> 0paa_count> 0image_urlpopulated
- Compare with HTML to ensure data matches
- Run batch test to verify consistency
- Pydantic Models: The openblog pipeline uses Pydantic models (
CitationList,InternalLinkList, etc.) which have specific methods liketo_dict_list(). - Key Name Mismatch: The integration script was written with assumed key names that don't match the actual pipeline output.
- No Validation: The extraction code didn't validate if keys exist before accessing them.
- Silent Failures: When keys don't exist, the code silently sets empty arrays/strings instead of logging warnings.
{
"citations": [
{"url": "https://...", "title": "...", "author": "..."},
...
],
"citations_count": 7,
"internal_links": [
{"url": "/magazine/...", "anchor_text": "...", "relevance": "..."},
...
],
"internal_links_count": 3,
"toc": {"Section 1": "section-1", ...},
"faq": [
{"question": "...", "answer": "..."},
...
],
"faq_count": 6,
"paa": [
{"question": "...", "answer": "..."},
...
],
"paa_count": 3,
"image_url": "https://drive.google.com/...",
"image_alt_text": "Article image: ...",
"image_prompt": "...",
"publication_date": "2025-12-09T..."
}100% - The data exists in the HTML, it's just not being extracted from parallel_results due to incorrect key names.
Fix Complexity: Low - Simple key name corrections in one file.
Impact: High - Will enable full UI display of enhanced data.