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

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

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

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

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

מדריך זה מניח שיש לכם:

אישור פרטי כניסה לאפליקציה בשולחן העבודה

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

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

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

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

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

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

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

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

היקפי ההרשאות הנדרשים לשיטה מסוימת מפורטים במסמכי התיעוד של השיטה. לדוגמה, ראו courses.courseWork.rubrics.create היקפי הרשאות. אפשר לראות את כל ההיקפים של Classroom בקטע היקפי ההרשאות של OAuth 2.0 לממשקי Google API. קריטריונים להערכה לא צוינו כאן כי ה-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 לקריטריון הערכה.

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

הצגה של מטלה בממשק המשתמש של 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

משוב

אם נתקלת בבעיות כלשהן או שיש לך משוב, אפשר לשלוח לנו משוב.