איך מתחילים לעבוד עם קריטריונים להערכה

rubric הוא תבנית שמורים יכולים להשתמש בה כדי לתת ציונים על עבודות שהתלמידים הגישו. באמצעות Classroom API תוכלו לפעול בשם המורה כדי לנהל את הקריטריונים האלה.

תצוגה של קריטריון למתן ציונים בממשק המשתמש של Classroom איור 1. דוגמה לקריטריון הערכה במטלה ב-Classroom.

במדריך הזה נסביר את המושגים הבסיסיים ואת הפונקציונליות של Rubrics API. במאמרים הבאים במרכז העזרה מוסבר על המבנה הכללי של קריטריון להערכת מטלה ועל אופן הערכת המטלות לפי קריטריון בממשק המשתמש של Classroom.

דרישות מוקדמות

במדריך הזה אנחנו יוצאים מנקודת הנחה שיש לכם:

מתן הרשאה לפרטי כניסה לאפליקציה למחשב

כדי לבצע אימות כמשתמש קצה ולגשת לנתוני המשתמשים באפליקציה, צריך ליצור מזהה לקוח אחד או יותר ב-OAuth 2.0. מזהה לקוח משמש לזיהוי אפליקציה אחת בשרתי OAuth של Google. אם האפליקציה פועלת בכמה פלטפורמות, צריך ליצור מזהה לקוח נפרד לכל פלטפורמה.

  1. נכנסים לדף Credentials ב-Google Cloud במסוף Google Cloud.
  2. לוחצים על Create Credentials (יצירת פרטי כניסה) > OAuth client ID (מזהה לקוח OAuth).
  3. לוחצים על Application type (סוג האפליקציה) > Desktop app (אפליקציה למחשב).
  4. בשדה Name, מקלידים שם לפרטי הכניסה. השם הזה מוצג רק במסוף Google Cloud. לדוגמה, 'Rubrics Preview client'.
  5. לוחצים על יצירה. יופיע המסך שנוצר על ידי לקוח OAuth, ותציג את מזהה הלקוח החדש ואת סוד הלקוח.
  6. לוחצים על הורדת קובץ JSON ואז על אישור. פרטי הכניסה שנוצרו מופיעים בקטע OAuth 2.0 Client IDs.
  7. שומרים את קובץ ה-JSON שהורדתם בתור credentials.json ומעבירים אותו לספריית העבודה.
  8. לוחצים על Create Credentials (יצירת פרטי כניסה) > API Key (מפתח API) ומתעדים את מפתח ה-API.

מידע נוסף זמין במאמר יצירת פרטי כניסה.

הגדרת היקפי הרשאות של OAuth

בהתאם להיקפי ה-OAuth הקיימים בפרויקט, יכול להיות שתצטרכו להגדיר היקפים נוספים.

  1. עוברים למסך ההסכמה של OAuth.
  2. לוחצים על עריכת האפליקציה > שמירה והמשך כדי להגיע למסך 'היקפים'.
  3. לוחצים על הוספה או הסרה של היקפים.
  4. מוסיפים את ההיקפים הבאים אם הם עדיין לא קיימים:
    • https://www.googleapis.com/auth/classroom.coursework.students
    • https://www.googleapis.com/auth/classroom.courses
  5. לאחר מכן לוחצים על עדכון > שמירה והמשך > שמירה והמשך > חזרה למרכז השליטה.

למידע נוסף, ראו הגדרת מסך ההסכמה של OAuth.

ההיקף classroom.coursework.students מאפשר גישת קריאה וכתיבה למסמכי הערכה (יחד עם גישה ל-CourseWork), והיקף ההרשאות classroom.courses מאפשר קריאה וכתיבה של קורסים.

ההיקפים הנדרשים לשיטה מסוימת מפורטים במסמכי העזרה של השיטה. לדוגמה, היקפי הרשאה של courses.courseWork.rubrics.create. אפשר לראות את כל היקפי ההרשאות של Classroom במאמר היקפי OAuth 2.0 ל-Google APIs. האפשרות 'קריטריונים' לא מוזכרת כאן כי ה-API עדיין נמצא בתצוגה מקדימה.

הגדרת הדוגמה

בספריית העבודה, מתקינים את ספריית הלקוח של Google ל-Python:

pip install --upgrade google-api-python-client google-auth-httplib2 google-auth-oauthlib

יוצרים קובץ בשם main.py שמאגר את ספריית הלקוח ומעניק הרשאה למשתמש, באמצעות מפתח ה-API במקום YOUR_API_KEY:

import json
import os.path

from google.auth.transport.requests import Request
from google.oauth2.credentials import Credentials
from google_auth_oauthlib.flow import InstalledAppFlow
from googleapiclient.discovery import build
from googleapiclient.errors import HttpError

# If modifying these scopes, delete the file token.json.
SCOPES = ['https://www.googleapis.com/auth/classroom.courses',
          'https://www.googleapis.com/auth/classroom.coursework.students']

def build_authenticated_service(api_key):
    """Builds the Classroom service."""
    creds = None
    # The file token.json stores the user's access and refresh tokens, and is
    # created automatically when the authorization flow completes for the first
    # time.
    if os.path.exists('token.json'):
        creds = Credentials.from_authorized_user_file('token.json', SCOPES)
    # If there are no (valid) credentials available, let the user log in.
    if not creds or not creds.valid:
        if creds and creds.expired and creds.refresh_token:
            creds.refresh(Request())
        else:
            flow = InstalledAppFlow.from_client_secrets_file(
                'credentials.json', SCOPES)
            creds = flow.run_local_server(port=0)
        # Save the credentials for the next run.
        with open('token.json', 'w') as token:
            token.write(creds.to_json())

    try:
        # Build the Classroom service.
        service = build(
            serviceName="classroom",
            version="v1",
            credentials=creds,
            discoveryServiceUrl=f"https://classroom.googleapis.com/$discovery/rest?labels=DEVELOPER_PREVIEW&key={api_key}")

        return service

    except HttpError as error:
        print('An error occurred: %s' % error)

if __name__ == '__main__':
    service = build_authenticated_service(YOUR_API_KEY)

מריצים את הסקריפט באמצעות python main.py. תתבקשו להיכנס לחשבון ולהסכים להיקפי של OAuth.

יצירת מטלה

קריטריון הערכה משויך למטלה, או ל-CourseWork, והוא רלוונטי רק בהקשר של ה-CourseWork הזה. רק משתמשים בפרויקט ב-Google Cloud שבו נוצר פריט ההורה CourseWork יכולים ליצור קריטריונים למתן ציונים. לצורך המדריך הזה, יוצרים מטלה חדשה מסוג CourseWork עם סקריפט.

מוסיפים את הפרטים הבאים ל-main.py:

def get_latest_course(service):
    """Retrieves the last created course."""
    try:
        response = service.courses().list(pageSize=1).execute()
        courses = response.get("courses", [])
        if not courses:
            print("No courses found. Did you remember to create one in the UI?")
            return
        course = courses[0]
        return course

    except HttpError as error:
        print(f"An error occurred: {error}")
        return error

def create_coursework(service, course_id):
    """Creates and returns a sample coursework."""
    try:
        coursework = {
            "title": "Romeo and Juliet analysis.",
            "description": """Write a paper arguing that Romeo and Juliet were
                                time travelers from the future.""",
            "workType": "ASSIGNMENT",
            "state": "PUBLISHED",
        }
        coursework = service.courses().courseWork().create(
            courseId=course_id, body=coursework).execute()
        return coursework

    except HttpError as error:
        print(f"An error occurred: {error}")
        return error

עכשיו מעדכנים את main.py כדי לאחזר את course_id של כיתה הבדיקה שיצרתם, יוצרים מטלה לדוגמה ומאחזרים את coursework_id של המטלה:

if __name__ == '__main__':
    service = build_authenticated_service(YOUR_API_KEY)

    course = get_latest_course(service)
    course_id = course.get("id")
    course_name = course.get("name")
    print(f"'{course_name}' course ID: {course_id}")

    coursework = create_coursework(service, course_id)
    coursework_id = coursework.get("id")
    print(f"Assignment created with ID {coursework_id}")

    #TODO(developer): Save the printed course and coursework IDs.

שומרים את course_id ואת coursework_id. הם נדרשים לכל פעולות ה-CRUD של הקריטריונים.

עכשיו אמורה להיות לכם דוגמה CourseWork ב-Classroom.

תצוגה של מטלה בממשק המשתמש של Classroom איור 2. תצוגה של מטלה לדוגמה ב-Classroom.

יצירת קריטריון הערכה

עכשיו אתם מוכנים להתחיל לנהל קריטריונים למתן ציונים.

אפשר ליצור קריטריון הערכה ב-CourseWork באמצעות קריאה ל-Create שמכילה את האובייקט המלא של הקריטריון להערכה. מאפייני המזהה של הקריטריונים והרמות מושמטים (הם נוצרים בזמן היצירה).

מוסיפים את הפונקציה הבאה ל-main.py:

def create_rubric(service, course_id, coursework_id):
    """Creates an example rubric on a coursework."""
    try:
        body = {
            "criteria": [
                {
                    "title": "Argument",
                    "description": "How well structured your argument is.",
                    "levels": [
                        {"title": "Convincing",
                         "description": "A compelling case is made.", "points": 30},
                        {"title": "Passable",
                         "description": "Missing some evidence.", "points": 20},
                        {"title": "Needs Work",
                         "description": "Not enough strong evidence..", "points": 0},
                    ]
                },
                {
                    "title": "Spelling",
                    "description": "How well you spelled all the words.",
                    "levels": [
                        {"title": "Perfect",
                         "description": "No mistakes.", "points": 20},
                        {"title": "Great",
                         "description": "A mistake or two.", "points": 15},
                        {"title": "Needs Work",
                         "description": "Many mistakes.", "points": 5},
                    ]
                },
                {
                    "title": "Grammar",
                    "description": "How grammatically correct your sentences are.",
                    "levels": [
                        {"title": "Perfect",
                         "description": "No mistakes.", "points": 20},
                        {"title": "Great",
                         "description": "A mistake or two.", "points": 15},
                        {"title": "Needs Work",
                         "description": "Many mistakes.", "points": 5},
                    ]
                },
            ]
        }

        rubric = service.courses().courseWork().rubrics().create(
            courseId=course_id, courseWorkId=coursework_id, body=body,
            # Specify the preview version. Rubrics CRUD capabilities are
            # supported in V1_20231110_PREVIEW and later.
            previewVersion="V1_20231110_PREVIEW"
            ).execute()
        print(f"Rubric created with ID {rubric.get('id')}")
        return rubric

    except HttpError as error:
        print(f"An error occurred: {error}")
        return error

לאחר מכן מעדכנים ומריצים את main.py כדי ליצור את מערכת הדירוג לדוגמה, באמצעות המזהים Course ו-CourseWork שציינתם קודם:

if __name__ == '__main__':
    service = build_authenticated_service(YOUR_API_KEY)

    rubric = create_rubric(service, YOUR_COURSE_ID, YOUR_COURSEWORK_ID)
    print(json.dumps(rubric, indent=4))

כמה נקודות לגבי ייצוג הקריטריון להערכה:

  • הסדר של הקריטריונים והרמות משתקף בממשק המשתמש של Classroom.
  • רמות עם ניקוד (אלה עם המאפיין points) חייבות להיות ממוינות לפי נקודות בסדר עולה או יורד (אי אפשר למיין אותן באופן אקראי).
  • המורים יכולים למיין מחדש את הקריטריונים והרמות עם הציונים (אבל לא את הרמות ללא ציונים) בממשק המשתמש, והסדר שלהם בנתונים ישתנה.

מגבלות – מידע נוסף על המגבלות של מבנה כלי הערכה.

חזרה לממשק המשתמש, שם מערכת הבקרה אמורה להופיע במטלה.

תצוגה של קריטריון למתן ציונים בממשק המשתמש של Classroom איור 3. דוגמה לקריטריון הערכה במטלה ב-Classroom.

קריאת קריטריון הערכה

אפשר לקרוא קריטריונים למתן ציונים באמצעות השיטות הסטנדרטיות List ו-Get.

למטלה יכול להיות לכל היותר קריטריון הערכה אחד, לכן יכול להיות שהתשובה ל-List לא תיראה לא אינטואיטיבית, אבל היא תעזור לכם אם אין לכם עדיין את מזהה קריטריון ההערכה. אם לא משויך ל-CourseWork קריטריון הערכה, התשובה List תהיה ריקה.

מוסיפים את הפונקציה הבאה ל-main.py:

def get_rubric(service, course_id, coursework_id):
    """
    Get the rubric on a coursework. There can only be at most one.
    Returns null if there is no rubric.
    """
    try:
        response = service.courses().courseWork().rubrics().list(
            courseId=course_id, courseWorkId=coursework_id,
            # Specify the preview version. Rubrics CRUD capabilities are
            # supported in V1_20231110_PREVIEW and later.
            previewVersion="V1_20231110_PREVIEW"
            ).execute()

        rubrics = response.get("rubrics", [])
        if not rubrics:
            print("No rubric found for this assignment.")
            return
        rubric = rubrics[0]
        return rubric

    except HttpError as error:
        print(f"An error occurred: {error}")
        return error

מעדכנים ומריצים את main.py כדי לאחזר את קריטריון ההערכה שהוספתם:

if __name__ == '__main__':
    service = build_authenticated_service(YOUR_API_KEY)

    rubric = get_rubric(service, YOUR_COURSE_ID, YOUR_COURSEWORK_ID)
    print(json.dumps(rubric, indent=4))

    #TODO(developer): Save the printed rubric ID.

חשוב לשים לב למאפיין id בקריטריון ההערכה לגבי השלבים הבאים.

Get פועל היטב כשיש לכם את מזהה כלי הערכה. השימוש ב-Get בפונקציה במקום זאת עשוי להיראות כך:

def get_rubric(service, course_id, coursework_id, rubric_id):
    """
    Get the rubric on a coursework. There can only be at most one.
    Returns a 404 if there is no rubric.
    """
    try:
        rubric = service.courses().courseWork().rubrics().get(
            courseId=course_id,
            courseWorkId=coursework_id,
            id=rubric_id,
            # Specify the preview version. Rubrics CRUD capabilities are
            # supported in V1_20231110_PREVIEW and later.
            previewVersion="V1_20231110_PREVIEW"
        ).execute()

        return rubric

    except HttpError as error:
        print(f"An error occurred: {error}")
        return error

ההטמעה הזו מחזירה שגיאת 404 אם אין קריטריון הערכה.

עדכון קריטריון הערכה

עדכונים של קריטריונים מתבצעים באמצעות קריאות ל-Patch. בגלל המבנה המורכב של קריטריון הערכה, צריך לבצע עדכונים לפי תבנית קריאה-שינוי-כתיבה, שבה כל נכס criteria מוחלף.

אלה כללי העדכון:

  1. קריטריונים או רמות שנוספים ללא מזהה נחשבים לתוספות.
  2. קריטריונים או רמות שאינם מוצגים נחשבים למחקות.
  3. קריטריונים או רמות עם מזהה קיים אבל עם נתונים ששונו נחשבים עריכות. מאפיינים שלא שונו יישארו כפי שהם.
  4. קריטריונים או רמות שצוינו עם מזהים חדשים או לא מוכרים נחשבים לשגיאות.
  5. הסדר של הקריטריונים והרמות החדשים נחשב לסדר החדש בממשק המשתמש (עם המגבלות שצוינו למעלה).

מוסיפים פונקציה לעדכון קריטריון הערכה:

def update_rubric(service, course_id, coursework_id, rubric_id, body):
    """
    Updates the rubric on a coursework.
    """
    try:
        rubric = service.courses().courseWork().rubrics().patch(
            courseId=course_id,
            courseWorkId=coursework_id,
            id=rubric_id,
            body=body,
            updateMask='criteria',
            # Specify the preview version. Rubrics CRUD capabilities are
            # supported in V1_20231110_PREVIEW and later.
            previewVersion="V1_20231110_PREVIEW"
        ).execute()

        return rubric

    except HttpError as error:
        print(f"An error occurred: {error}")
        return error

בדוגמה הזו, השדה criteria צוין לשינוי באמצעות updateMask.

לאחר מכן משנים את main.py כדי לבצע שינוי בכל אחד מכללי העדכון שצוינו למעלה:

if __name__ == '__main__':
    service = build_authenticated_service(YOUR_API_KEY)

    # Get the latest rubric.
    rubric = get_rubric(service, YOUR_COURSE_ID, YOUR_COURSEWORK_ID)
    criteria = rubric.get("criteria")
    """
    The "criteria" property should look like this:
    [
        {
            "id": "NkEyMdMyMzM2Nxkw",
            "title": "Argument",
            "description": "How well structured your argument is.",
            "levels": [
                {
                    "id": "NkEyMdMyMzM2Nxkx",
                    "title": "Convincing",
                    "description": "A compelling case is made.",
                    "points": 30
                },
                {
                    "id": "NkEyMdMyMzM2Nxky",
                    "title": "Passable",
                    "description": "Missing some evidence.",
                    "points": 20
                },
                {
                    "id": "NkEyMdMyMzM2Nxkz",
                    "title": "Needs Work",
                    "description": "Not enough strong evidence..",
                    "points": 0
                }
            ]
        },
        {
            "id": "NkEyMdMyMzM2Nxk0",
            "title": "Spelling",
            "description": "How well you spelled all the words.",
            "levels": [...]
        },
        {
            "id": "NkEyMdMyMzM2Nxk4",
            "title": "Grammar",
            "description": "How grammatically correct your sentences are.",
            "levels": [...]
        }
    ]
    """

    # Make edits. This example will make one of each type of change.

    # Add a new level to the first criteria. Levels must remain sorted by
    # points.
    new_level = {
        "title": "Profound",
        "description": "Truly unique insight.",
        "points": 50
    }
    criteria[0]["levels"].insert(0, new_level)

    # Remove the last criteria.
    del criteria[-1]

    # Update the criteria titles with numeric prefixes.
    for index, criterion in enumerate(criteria):
        criterion["title"] = f"{index}: {criterion['title']}"

    # Resort the levels from descending to ascending points.
    for criterion in criteria:
        criterion["levels"].sort(key=lambda level: level["points"])

    # Update the rubric with a patch call.
    new_rubric = update_rubric(
        service, YOUR_COURSE_ID, YOUR_COURSEWORK_ID, YOUR_RUBRIC_ID, rubric)

    print(json.dumps(new_rubric, indent=4))

השינויים אמורים לבוא לידי ביטוי אצל המורה ב-Classroom.

תצוגה של קריטריון מעודכן בממשק המשתמש של Classroom איור 4. תצוגה של הקריטריון המעודכן.

הצגת מטלות עם ציון לפי קריטריון הערכה

בשלב זה, לא ניתן לתת ציון להגשות של תלמידים באמצעות קריטריון הערכה באמצעות ה-API, אבל אפשר לקרוא את קריטריוני ההערכה במטלות עם קריטריון הערכה בממשק המשתמש של Classroom.

בתור תלמידים, בממשק המשתמש של Classroom, מגישים את המטלה לדוגמה. לאחר מכן, המורה יכול לתת ציון למטלה באופן ידני באמצעות קריטריון ההערכה.

הצגת ציון לפי קריטריון הערכה בממשק המשתמש של Classroom איור 5. תצוגת המורה של קריטריון ההערכה במהלך מתן ציונים.

להגשות של תלמידים שקיבלו ציון באמצעות קריטריונים יש שני מאפיינים חדשים: draftRubricGrades ו-assignedRubricGrades, שמייצגים את הנקודות והרמות שבחר המורה במצבי הטיוטות והציונים שהוקצו, בהתאמה.

בנוסף, הגשות של תלמידים עם קריטריון הערכה משויך מכילות את השדה rubricId, גם לפני מתן הציון. הערך הזה מייצג את מערכת הדירוג האחרונה שמשויכת למטלה CourseWork, והוא עשוי להשתנות אם המורים מוחקים מערכת דירוג ויוצרים אותה מחדש.

אפשר להשתמש בשיטות הקיימות studentSubmissions.Get ו-studentSubmissions.List כדי להציג את המטלות שהתלמידים הגישו וקיבלתם עליהן ציונים.

כדי להציג את רשימת ההגשות של התלמידים, צריך להוסיף את הפונקציה הבאה אל main.py:

def get_latest_submission(service, course_id, coursework_id):
    """Retrieves the last submission for an assignment."""
    try:
        response = service.courses().courseWork().studentSubmissions().list(
            courseId = course_id,
            courseWorkId = coursework_id,
            pageSize=1,
            # Specify the preview version. Rubrics CRUD capabilities are
            # supported in V1_20231110_PREVIEW and later.
            previewVersion="V1_20231110_PREVIEW"
        ).execute()
        submissions = response.get("studentSubmissions", [])
        if not submissions:
            print(
                """No submissions found. Did you remember to turn in and grade
                   the assignment in the UI?""")
            return
        submission = submissions[0]
        return submission

    except HttpError as error:
        print(f"An error occurred: {error}")
        return error

אחר כך מעדכנים ומריצים את הפקודה main.py כדי לראות את הציונים בהגשה.

if __name__ == '__main__':
    service = build_authenticated_service(YOUR_API_KEY)

    submission = get_latest_submission(
        service, YOUR_COURSE_ID, YOUR_COURSEWORK_ID)
    print(json.dumps(submission, indent=4))

השדות draftRubricGrades ו-assignedRubricGrades מכילים את הפרטים הבאים:

  • הערך של criterionId בקריטריונים המתאימים של כלי הערכה.
  • הערך של points שהמורה הקצתה לכל קריטריון. יכול להיות שהיא נובעת מהרמה שנבחרה, אבל יכול להיות גם שהמורה ביצע שינוי.
  • הערך של levelId ברמה שנבחרה לכל קריטריון. אם המורה לא בחר רמה, אבל עדיין הקצה נקודות לפי הקריטריון, השדה הזה לא יופיע.

הרשימות האלה מכילות רק את הקריטריונים שבהם המורה בחר/ה רמה או מגדיר/ה נקודות. לדוגמה, אם מורה בוחר לבצע אינטראקציה רק עם קריטריון אחד במהלך מתן הציונים, draftRubricGrades ו-assignedRubricGrades יכללו רק פריט אחד, גם אם לקריטריון יש הרבה קריטריונים.

מחיקת קריטריון הערכה

אפשר למחוק קריטריון הערכה באמצעות בקשה רגילה מסוג Delete. הקוד הבא מציג פונקציית דוגמה לצורך השלמות, אבל מאחר שההערכה כבר החלה, אי אפשר למחוק את מערכת הדירוג הנוכחית:

def delete_rubric(service, course_id, coursework_id, rubric_id):
    """Deletes the rubric on a coursework."""
    try:
        service.courses().courseWork().rubrics().delete(
            courseId=course_id,
            courseWorkId=coursework_id,
            id=rubric_id,
            # Specify the preview version. Rubrics CRUD capabilities are
            # supported in V1_20231110_PREVIEW and later.
            previewVersion="V1_20231110_PREVIEW"
        ).execute()

    except HttpError as error:
        print(f"An error occurred: {error}")
        return error

ייצוא וייבוא של קריטריונים

אפשר לייצא ידנית את הקריטריונים של ההערכה לגיליונות אלקטרוניים של Google לשימוש חוזר של מורים.

בנוסף לציון קריטריונים של קריטריונים בקוד, אפשר ליצור ולעדכן קריטריונים מהגיליונות המיוצאים האלה על ידי ציון הערך sourceSpreadsheetId בגוף הקריטריון במקום criteria:

def create_rubric_from_sheet(service, course_id, coursework_id, sheet_id):
    """Creates an example rubric on a coursework."""
    try:
        body = {
            "sourceSpreadsheetId": sheet_id
        }

        rubric = service.courses().courseWork().rubrics().create(
            courseId=course_id, courseWorkId=coursework_id, body=body,
            # Specify the preview version. Rubrics CRUD capabilities are
            # supported in V1_20231110_PREVIEW and later.
            previewVersion="V1_20231110_PREVIEW"
            ).execute()

        print(f"Rubric created with ID {rubric.get('id')}")
        return rubric

    except HttpError as error:
        print(f"An error occurred: {error}")
        return error

משוב

אם נתקלתם בבעיות או שיש לכם משוב, תוכלו לשלוח לנו משוב.