Learning Metrics Dashboard
L3
NotionPython Roadmap
Create a comprehensive Learning Metrics Dashboard section displaying precise statistics and recommendations based on the Steps database.
Created by Lingjun Chen
2025-08-02
Data AggregationConditional FilteringReport GenerationVisual Formatting
Model Ranking
Click on the dots to view the trajectory of each task run
Model | Run Results | Pass@4 | Pass^4 | Avg Time | Avg Turns | Input Tokens | Output Tokens | Total Tokens |
---|---|---|---|---|---|---|---|---|
claude-4-1-opus | 0 /1 | - | - | 272.9s | 11.0 | 364,570 | 4,207 | 368,777 |
claude-4-sonnet | 0 /4 | 131.9s | 12.3 | 430,278 | 3,600 | 433,879 | ||
deepseek-chat | 0 /4 | 197.1s | 10.5 | 344,350 | 2,260 | 346,610 | ||
gemini-2-5-pro | 0 /4 | 175.1s | 6.0 | 210,153 | 15,398 | 225,551 | ||
gpt-5 | 0 /4 | 843.8s | 12.8 | 529,015 | 51,128 | 580,144 | ||
grok-4 | 0 /4 | - | - | - | - | - | ||
k2 | 0 /4 | 98.8s | 7.8 | 139,875 | 826 | 140,701 | ||
o3 | 0 /4 | 273.8s | 8.5 | 177,491 | 15,773 | 193,264 | ||
qwen-3-coder | 0 /4 | 357.7s | 34.0 | 2,120,040 | 5,356 | 2,125,396 |
Task State
Notion Workspace
This task is executed based on this Notion workspace
This workspace is cloned from notion official template marketplace.View Original Template
Instruction
Verify
Python
import sys
from notion_client import Client
from tasks.utils import notion_utils
def get_page_title_from_result(page_result):
"""
Extract the title from a page result object from database query.
"""
properties = page_result.get('properties', {})
# Try common title property names
for prop_name in ['Name', 'Title', 'title', 'Lessons']:
if prop_name in properties:
prop = properties[prop_name]
if prop.get('type') == 'title':
title_array = prop.get('title', [])
if title_array and len(title_array) > 0:
return title_array[0].get('plain_text', '')
return ''
def verify(notion: Client, main_id: str = None) -> bool:
"""
Verifies that the Learning Metrics Dashboard has been implemented correctly according to description.md.
"""
# Step 1: Find the main page and get all blocks
if main_id:
found_id, object_type = notion_utils.find_page_or_database_by_id(notion, main_id)
if not found_id or object_type != 'page':
print("Error: Main page not found.", file=sys.stderr)
return False
else:
# Try to find the main page by searching
found_id = notion_utils.find_page(notion, "Python Roadmap")
if not found_id:
print("Error: Main page not found.", file=sys.stderr)
return False
print(f"Found main page: {found_id}")
# Get Steps database to calculate expected statistics
steps_db_id = notion_utils.find_database(notion, "Steps")
if not steps_db_id:
print("Error: Steps database not found.", file=sys.stderr)
return False
# Query Steps database to get all lessons
steps_data = notion.databases.query(database_id=steps_db_id)
total_lessons = len(steps_data['results'])
completed_count = 0
in_progress_count = 0
completed_lessons = []
# Get Chapters database for level information
chapters_db_id = notion_utils.find_database(notion, "Chapters")
if not chapters_db_id:
print("Error: Chapters database not found.", file=sys.stderr)
return False
# Query Chapters database to get level information
chapters_data = notion.databases.query(database_id=chapters_db_id)
level_ids = {
'Beginner Level': None,
'Intermediate Level': None,
'Advanced Level': None
}
for chapter in chapters_data['results']:
chapter_name = get_page_title_from_result(chapter)
if chapter_name in level_ids:
level_ids[chapter_name] = chapter['id']
# Initialize level counts
level_counts = {
'Beginner Level': {'total': 0, 'completed': 0},
'Intermediate Level': {'total': 0, 'completed': 0},
'Advanced Level': {'total': 0, 'completed': 0}
}
# Count lessons by status and level
for lesson in steps_data['results']:
status = lesson['properties']['Status']['status']
if status and status['name'] == 'Done':
completed_count += 1
lesson_title = get_page_title_from_result(lesson)
if lesson_title:
completed_lessons.append(lesson_title)
elif status and status['name'] == 'In Progress':
in_progress_count += 1
# Count by level
chapters_relation = lesson['properties']['Chapters']['relation']
for chapter_ref in chapters_relation:
chapter_id = chapter_ref['id']
for level_name, level_id in level_ids.items():
if chapter_id == level_id:
level_counts[level_name]['total'] += 1
if status and status['name'] == 'Done':
level_counts[level_name]['completed'] += 1
# Calculate percentages
completed_percentage = round((completed_count / total_lessons * 100), 1) if total_lessons > 0 else 0
in_progress_percentage = round((in_progress_count / total_lessons * 100), 1) if total_lessons > 0 else 0
print(f"Expected statistics:")
print(f" Total Lessons: {total_lessons}")
print(f" Completed: {completed_count} ({completed_percentage}%)")
print(f" In Progress: {in_progress_count} ({in_progress_percentage}%)")
print(f" Beginner Level: {level_counts['Beginner Level']['total']} lessons ({level_counts['Beginner Level']['completed']} completed)")
print(f" Intermediate Level: {level_counts['Intermediate Level']['total']} lessons ({level_counts['Intermediate Level']['completed']} completed)")
print(f" Advanced Level: {level_counts['Advanced Level']['total']} lessons ({level_counts['Advanced Level']['completed']} completed)")
print(f" Completed lessons (first 5): {completed_lessons[:5]}")
# Get all blocks from the page
all_blocks = notion_utils.get_all_blocks_recursively(notion, found_id)
print(f"Found {len(all_blocks)} blocks")
# Step 2: Verify the required elements in order
learning_materials_idx = -1
dashboard_heading_idx = -1
callout_idx = -1
toggle_idx = -1
whether_paragraph_idx = -1 # Track the "Whether you're starting from scratch" paragraph
# Track what we've verified
callout_has_brown_bg = False
callout_has_no_icon = False
callout_has_course_statistics_title = False
callout_title_has_correct_colors = False
statistics_items_found = []
completed_topics_found = []
# Expected statistics content
expected_statistics = [
f"Total Lessons: {total_lessons}",
f"Completed: {completed_count} ({completed_percentage}%)",
f"In Progress: {in_progress_count} ({in_progress_percentage}%)",
f"Beginner Level: {level_counts['Beginner Level']['total']} lessons ({level_counts['Beginner Level']['completed']} completed)",
f"Intermediate Level: {level_counts['Intermediate Level']['total']} lessons ({level_counts['Intermediate Level']['completed']} completed)",
f"Advanced Level: {level_counts['Advanced Level']['total']} lessons ({level_counts['Advanced Level']['completed']} completed)"
]
# Check blocks in order
for i, block in enumerate(all_blocks):
if block is None:
continue
block_type = block.get("type")
# 1. Check for Learning Materials heading (requirement 1)
if learning_materials_idx == -1 and block_type == "heading_3":
block_text = notion_utils.get_block_plain_text(block)
if "🎓 Learning Materials" in block_text or "Learning Materials" in block_text:
learning_materials_idx = i
print(f"✓ Requirement 1: Found Learning Materials heading at position {i}")
# 2. Check for Learning Metrics Dashboard heading after Learning Materials (requirement 2)
elif learning_materials_idx != -1 and dashboard_heading_idx == -1 and block_type == "heading_3":
block_text = notion_utils.get_block_plain_text(block)
if "📊 Learning Metrics Dashboard" in block_text:
dashboard_heading_idx = i
print(f"✓ Requirement 2: Found Learning Metrics Dashboard heading at position {i}")
# 3. Check for callout block after Dashboard heading (requirement 3)
elif dashboard_heading_idx != -1 and callout_idx == -1 and block_type == "callout":
callout_idx = i
print(f" Found callout block at position {i}")
# Check brown background (requirement 3.1)
if block.get("callout", {}).get("color") == "brown_background":
callout_has_brown_bg = True
print(f" ✓ Requirement 3.1: Callout has brown background")
# Check no icon (requirement 3.2)
icon = block.get("callout", {}).get("icon")
if icon is None:
callout_has_no_icon = True
print(f" ✓ Requirement 3.2: Callout has no icon")
# Get nested blocks for Course Statistics title and content
nested_blocks = notion_utils.get_all_blocks_recursively(notion, block.get("id"))
for nested in nested_blocks:
# Check for heading_3 only as per requirement
if nested and nested.get("type") == "heading_3":
# Check for "Course Statistics" title with correct formatting
rich_text = nested.get("heading_3", {}).get("rich_text", [])
course_found = False
course_correct = False
statistics_found = False
statistics_correct = False
for text_item in rich_text:
text_content = text_item.get("text", {}).get("content", "")
annotations = text_item.get("annotations", {})
color = annotations.get("color", "default")
is_bold = annotations.get("bold", False)
if "Course" in text_content:
course_found = True
# Check if Course is blue and bold
if color == "blue" and is_bold:
course_correct = True
print(f" ✓ 'Course' has blue color and is bold")
else:
print(f" ✗ 'Course' color: {color}, bold: {is_bold} (should be blue and bold)")
if "Statistics" in text_content:
statistics_found = True
# Check if Statistics is yellow and bold
if color == "yellow" and is_bold:
statistics_correct = True
print(f" ✓ 'Statistics' has yellow color and is bold")
else:
print(f" ✗ 'Statistics' color: {color}, bold: {is_bold} (should be yellow and bold)")
if course_found and statistics_found:
callout_has_course_statistics_title = True
if course_correct and statistics_correct:
callout_title_has_correct_colors = True
print(f" ✓ Requirement 3.3: Callout has 'Course Statistics' title with correct colors")
else:
print(f" ✗ Requirement 3.3: Title found but colors/formatting incorrect")
# Check for statistics items in bulleted list
elif nested and nested.get("type") == "bulleted_list_item":
item_text = notion_utils.get_block_plain_text(nested)
for expected_item in expected_statistics:
if expected_item in item_text:
if expected_item not in statistics_items_found:
statistics_items_found.append(expected_item)
print(f" ✓ Requirement 3.4: Found statistics item: {expected_item}")
# 4. Check for Completed Topics toggle after callout (requirement 4)
elif callout_idx != -1 and toggle_idx == -1 and block_type == "toggle":
block_text = notion_utils.get_block_plain_text(block)
if "🏆 Completed Topics (Click to expand)" in block_text:
toggle_idx = i
print(f"✓ Requirement 4: Found Completed Topics toggle at position {i}")
# Get nested blocks for completed topics list
nested_blocks = notion_utils.get_all_blocks_recursively(notion, block.get("id"))
for nested in nested_blocks:
if nested and nested.get("type") == "numbered_list_item":
item_text = notion_utils.get_block_plain_text(nested)
if item_text and item_text in completed_lessons:
completed_topics_found.append(item_text)
print(f" ✓ Requirement 4.1: Found completed topic: {item_text}")
# 5. Check for "Whether you're starting from scratch" paragraph (should be after dashboard content)
elif block_type == "paragraph" and whether_paragraph_idx == -1:
block_text = notion_utils.get_block_plain_text(block)
if "Whether you're starting from scratch" in block_text or "Whether you're starting from scratch" in block_text:
whether_paragraph_idx = i
print(f" Found 'Whether you're starting from scratch' paragraph at position {i}")
# Step 3: Verify all requirements were met
print(f"\nVerification Summary:")
all_passed = True
# Requirement 1: Learning Materials section found
if learning_materials_idx == -1:
print("✗ Requirement 1: Learning Materials section NOT found", file=sys.stderr)
all_passed = False
else:
print("✓ Requirement 1: Learning Materials section found")
# Requirement 2: Learning Metrics Dashboard heading after Learning Materials and before "Whether..." paragraph
if dashboard_heading_idx == -1:
print("✗ Requirement 2: Learning Metrics Dashboard heading NOT found", file=sys.stderr)
all_passed = False
elif dashboard_heading_idx <= learning_materials_idx:
print("✗ Requirement 2: Learning Metrics Dashboard heading not AFTER Learning Materials", file=sys.stderr)
all_passed = False
elif whether_paragraph_idx != -1 and dashboard_heading_idx >= whether_paragraph_idx:
print("✗ Requirement 2: Learning Metrics Dashboard heading not BEFORE 'Whether you're starting from scratch' paragraph", file=sys.stderr)
all_passed = False
else:
print("✓ Requirement 2: Learning Metrics Dashboard heading found after Learning Materials")
if whether_paragraph_idx != -1:
print(" ✓ Dashboard content is correctly placed before 'Whether you're starting from scratch' paragraph")
# Requirement 3: Course Statistics callout block with all specifications
if callout_idx == -1:
print("✗ Requirement 3: Course Statistics callout block NOT found", file=sys.stderr)
all_passed = False
else:
if not callout_has_brown_bg:
print("✗ Requirement 3.1: Callout does NOT have brown background", file=sys.stderr)
all_passed = False
else:
print("✓ Requirement 3.1: Callout has brown background")
if not callout_has_no_icon:
print("✗ Requirement 3.2: Callout has an icon (should have none)", file=sys.stderr)
all_passed = False
else:
print("✓ Requirement 3.2: Callout has no icon")
if not callout_has_course_statistics_title:
print("✗ Requirement 3.3: Callout does NOT have 'Course Statistics' title", file=sys.stderr)
all_passed = False
else:
print("✓ Requirement 3.3: Callout has 'Course Statistics' title")
if not callout_title_has_correct_colors:
print("✗ Requirement 3.3.1: Title does NOT have correct colors (blue for Course, yellow for Statistics)", file=sys.stderr)
all_passed = False
else:
print("✓ Requirement 3.3.1: Title has correct colors")
# Check all statistics items
missing_items = [item for item in expected_statistics if item not in statistics_items_found]
if missing_items:
print(f"✗ Requirement 3.4: Missing statistics items: {missing_items}", file=sys.stderr)
all_passed = False
else:
print("✓ Requirement 3.4: All 6 statistics items found")
# Requirement 4: Completed Topics toggle
if toggle_idx == -1:
print("✗ Requirement 4: Completed Topics toggle NOT found", file=sys.stderr)
all_passed = False
elif toggle_idx <= callout_idx:
print("✗ Requirement 4: Completed Topics toggle not AFTER callout", file=sys.stderr)
all_passed = False
else:
print("✓ Requirement 4: Completed Topics toggle found after callout")
# Check that exactly 5 completed topics are listed
if len(completed_topics_found) != 5:
if len(completed_topics_found) < 5:
print(f"✗ Requirement 4.1: Only {len(completed_topics_found)} completed topics found (need exactly 5)", file=sys.stderr)
else:
print(f"✗ Requirement 4.1: Found {len(completed_topics_found)} completed topics (need exactly 5, not more)", file=sys.stderr)
all_passed = False
else:
print(f"✓ Requirement 4.1: Found exactly 5 completed topics as required")
# Requirement 5: Proper integration (implicitly checked by order)
if all_passed:
print("✓ Requirement 5: All content properly integrated in correct order")
return all_passed
def main():
"""
Executes the verification process and exits with a status code.
"""
notion = notion_utils.get_notion_client()
main_id = sys.argv[1] if len(sys.argv) > 1 else None
if verify(notion, main_id):
print("Verification passed")
sys.exit(0)
else:
print("Verification failed")
sys.exit(1)
if __name__ == "__main__":
main()