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 |
|---|---|---|---|---|---|---|---|---|
Model | Run Results | Pass@4 | Pass^4 | Avg Time | Avg Turns | Input Tokens | Output Tokens | Total Tokens |
claude-opus-4-1 | 0 /1 | - | - | 272.9s | 11.0 | 364,570 | 4,207 | 368,777 |
claude-sonnet-4 | 0 /4 | 131.9s | 12.3 | 430,278 | 3,600 | 433,879 | ||
claude-sonnet-4-high | 0 /4 | 118.3s | 11.3 | 756,682 | 3,400 | 760,081 | ||
claude-sonnet-4-low | 0 /4 | 139.0s | 12.8 | 811,717 | 4,526 | 816,243 | ||
deepseek-chat | 0 /4 | 197.1s | 10.5 | 344,350 | 2,260 | 346,610 | ||
gemini-2-5-flash | 0 /4 | 124.7s | 6.8 | 300,653 | 24,305 | 324,958 | ||
gemini-2-5-pro | 0 /4 | 195.9s | 7.5 | 267,020 | 17,764 | 284,784 | ||
glm-4-5 | 0 /4 | 222.6s | 15.3 | 396,899 | 5,613 | 402,512 | ||
gpt-4-1 | 0 /4 | 25.7s | 5.8 | 87,756 | 626 | 88,381 | ||
gpt-4-1-mini | 0 /4 | 50.4s | 7.5 | 242,408 | 1,403 | 243,811 | ||
gpt-4-1-nano | 0 /4 | 69.1s | 9.8 | 52,000 | 8,982 | 60,982 | ||
gpt-5-high | 0 /4 | 1610.0s | 13.8 | 377,330 | 76,664 | 453,994 | ||
gpt-5-low | 0 /4 | 843.8s | 12.8 | 529,015 | 51,128 | 580,144 | ||
gpt-5-medium | 0 /4 | 1035.1s | 13.0 | 526,007 | 53,698 | 579,706 | ||
gpt-5-mini-high | 0 /4 | 978.7s | 18.8 | 1,740,461 | 86,519 | 1,826,979 | ||
gpt-5-mini-low | 0 /4 | 94.3s | 7.8 | 381,035 | 7,769 | 388,803 | ||
gpt-5-mini-medium | 0 /4 | 259.5s | 12.5 | 877,482 | 21,425 | 898,907 | ||
gpt-5-nano-high | 0 /4 | 201.8s | 4.3 | 176,659 | 39,032 | 215,691 | ||
gpt-5-nano-low | 0 /4 | 31.0s | 1.5 | 12,438 | 5,839 | 18,277 | ||
gpt-5-nano-medium | 0 /4 | 100.2s | 3.8 | 121,473 | 16,998 | 138,470 | ||
gpt-oss-120b | 0 /4 | 13.0s | 3.5 | 27,211 | 598 | 27,809 | ||
grok-4 | 0 /4 | 649.0s | 23.5 | 1,078,861 | 12,405 | 1,091,266 | ||
grok-code-fast-1 | 0 /4 | 250.2s | 24.0 | 731,959 | 6,967 | 741,144 | ||
kimi-k2-0711 | 0 /4 | 107.4s | 11.8 | 309,737 | 2,473 | 312,210 | ||
kimi-k2-0905 | 0 /4 | 876.6s | 46.3 | 2,325,116 | 10,484 | 2,335,600 | ||
o3 | 0 /4 | 273.8s | 8.5 | 177,491 | 15,773 | 193,264 | ||
o4-mini | 0 /4 | 486.8s | 6.8 | 110,526 | 21,093 | 131,619 | ||
qwen-3-coder-plus | 0 /4 | 112.8s | 20.0 | 1,004,570 | 2,853 | 1,007,423 | ||
qwen-3-max | 0 /4 | 140.3s | 14.0 | 628,474 | 3,830 | 632,304 |
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
Task: Learning Metrics Dashboard
Objective
Create a comprehensive Learning Metrics Dashboard section in the Python Roadmap page that displays precise statistics and recommendations based on the Steps database content.
Requirements
1. Section Placement
- Add new content immediately after the Learning Materials section (before
Whether you're starting from scratch or).
2. Dashboard Header
- Type: heading_3
- Text:
📊 Learning Metrics Dashboard
3. Course Statistics Block
- Type: callout
- Background Color: Brown
- Icon: None
- Title: Course Statistics (bold, heading_3). Use the same color scheme as other callout headings.
- Content: Bulleted list with the following items in exact order:
Total Lessons: [X](count all entries in Steps database)Completed: [X] ([Y]%)(count Status="Done", calculate percentage to 1 decimal)In Progress: [X] ([Y]%)(count Status="In Progress", calculate percentage to 1 decimal)Beginner Level: [X] lessons ([Y] completed)(filter by Chapters relation to Beginner Level)Intermediate Level: [X] lessons ([Y] completed)(filter by Chapters relation to Intermediate Level)Advanced Level: [X] lessons ([Y] completed)(filter by Chapters relation to Advanced Level)
4. Completed Topics Section
- Type: toggle
- Text:
🏆 Completed Topics (Click to expand) - Nested Content: Numbered list containing exactly 5 items
- List lessons with Status="Done"
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()