開始使用評分量表

rubric 是老師評分學生提交內容時可使用的範本。Classroom API 可讓您代表老師管理這些評量標準,以及讀取學生提交作業的評量標準成績。

Classroom 使用者介面中的評分量表 圖 1. 查看 Classroom 作業的範例評分量表。

本指南說明 Rubrics API 的基本概念和功能。請參閱這些說明中心文章,瞭解評量表的一般結構,以及如何在 Classroom UI 中評分

必要條件

本指南假設您具備下列條件:

授權電腦版應用程式的憑證

如要以使用者身分驗證,並存取應用程式中的使用者資料,您需要建立一或多個 OAuth 2.0 用戶端 ID。用戶端 ID 可讓 Google 的 OAuth 伺服器識別單一應用程式。如果您的應用程式在多個平台上執行,則必須為每個平台建立專屬的用戶端 ID。

  1. 前往 Google Cloud 控制台的「憑證」頁面。
  2. 依序點選「建立憑證」 >「OAuth 用戶端 ID」
  3. 依序點選「應用程式類型」 >「桌面應用程式」
  4. 在「Name」欄位中輸入憑證名稱。這個名稱只會顯示在 Google Cloud 控制台中。例如「Rubrics client」。
  5. 按一下「建立」,系統會顯示「OAuth client created」(已建立 OAuth 用戶端) 畫面,顯示新的用戶端 ID 和用戶端密碼。
  6. 依序按一下「Download JSON」和「OK」。新建立的憑證會顯示在 OAuth 2.0 用戶端 ID 下方。
  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 授權範圍 範例。您可以在「Google API 適用的 OAuth 2.0 範圍」中查看所有 Classroom 範圍。

設定範例

在工作目錄中安裝 Python 適用的 Google 用戶端程式庫:

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 的情況下才有意義。只有建立父項 CourseWork 項目的 Google Cloud 專案才能建立評量標準。為了配合本指南的說明,請使用指令碼建立新的 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_idcoursework_id。所有評量基準 CRUD 作業都需要這些屬性。

您現在應該會在 Classroom 中看到範例 CourseWork

Classroom UI 中的作業檢視畫面 圖 2. Classroom 中的範例作業畫面。

檢查使用者資格

如要建立及更新評量標準,提出要求的使用者和相應的課程擁有者都必須具備 Google Workspace for Education Plus 授權。Classroom 支援使用者的資格端點,方便開發人員判斷使用者可存取哪些功能。

更新並執行 main.py,確認測試帳戶可存取評量標準功能:

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

    capability = service.userProfiles().checkUserCapability(
        userId='me',
        # Specify the preview version. checkUserCapability is
        # supported in V1_20240930_PREVIEW and later.
        previewVersion="V1_20240930_PREVIEW",
        capability="CREATE_RUBRIC").execute()

    if not capability.get('allowed'):
      print('User ineligible for rubrics creation.')
      # TODO(developer): in a production app, this signal could be used to
      # proactively hide any rubrics related features from users or encourage
      # them to upgrade to the appropriate license.
    else:
      print('User eligible for rubrics creation.')

建立評分量表

您現在可以開始管理評量標準了。

您可以使用包含完整評分量表物件的 create() 呼叫,在 CourseWork 上建立評分量表,其中會省略準則和等級的 ID 屬性 (這些會在建立時產生)。

將下列函式新增至 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
            ).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,使用先前建立的 CourseCourseWork ID 建立範例評量標準:

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

    capability = service.userProfiles().checkUserCapability(
        userId='me',
        # Specify the preview version. checkUserCapability is
        # supported in V1_20240930_PREVIEW and later.
        previewVersion="V1_20240930_PREVIEW",
        capability="CREATE_RUBRIC").execute()

    if not capability.get('allowed'):
      print('User ineligible for rubrics creation.')
      # TODO(developer): in a production app, this signal could be used to
      # proactively hide any rubrics related features from users or encourage
      # them to upgrade to the appropriate license.
    else:
      rubric = create_rubric(service, YOUR_COURSE_ID, YOUR_COURSEWORK_ID)
      print(json.dumps(rubric, indent=4))

關於評分標準表示法的幾點說明:

  • 準則和等級順序會顯示在 Classroom 使用者介面中。
  • 分數等級 (具有 points 屬性) 必須依分數以遞增或遞減順序排序 (不能隨機排序)。
  • 老師可以在 UI 中重新排序條件和評分層級 (但無法排序未評分層級),並變更資料中的順序。

如要進一步瞭解評分量表結構的限制,請參閱限制

回到使用者介面,您應該會在作業中看到評分標準。

Classroom 使用者介面中的評分量表 圖 3. 查看 Classroom 作業的範例評分量表。

查看評分量表

您可以使用標準的 list()get() 方法讀取評量標準。

作業最多只能包含一個評分量表,因此 list() 可能不太直覺,但如果您還沒有評分量表 ID,這項功能就很實用。如果沒有與 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
            ).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() 在您有評分標準 ID 的情況下運作良好。在函式中使用 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
        ).execute()

        return rubric

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

如果沒有評量標準,這個實作會傳回 404。

更新評分量表

您可以使用 patch() 呼叫更新評量標準。由於評量標準的結構複雜,更新作業必須使用讀取-修改-寫入模式,並取代整個 criteria 屬性。

更新規則如下:

  1. 不含 ID 的條件或等級視為新增
  2. 之前缺少的條件或層級視為刪除
  3. 若評估標準或等級具有現有 ID,但資料已經過修改,則視為編輯。未修改的屬性則維持原樣。
  4. 使用新 ID 或不明 ID提供的條件或等級會視為錯誤
  5. 新版評估標準和等級的順序會視為新版 UI 的順序 (但仍有上述限制)。

新增用於更新評量標準的函式:

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'
        ).execute()

        return rubric

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

在這個範例中,我們指定使用 updateMask 修改 criteria 欄位。

接著修改 main.py,針對上述各項更新規則進行變更:

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

    capability = service.userProfiles().checkUserCapability(
        userId='me',
        # Specify the preview version. checkUserCapability is
        # supported in V1_20240930_PREVIEW and later.
        previewVersion="V1_20240930_PREVIEW",
        capability="CREATE_RUBRIC").execute()

    if not capability.get('allowed'):
      print('User ineligible for rubrics creation.')
      # TODO(developer): in a production app, this signal could be used to
      # proactively hide any rubrics related features from users or encourage
      # them to upgrade to the appropriate license.
    else:
        # 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 UI 查看已使用評分量表評分的作業評分。

以學生身分登入 Classroom 使用者介面,完成並繳交範例作業。 接著,老師可以使用評分量表手動評分作業

在 Classroom 使用者介面中查看評分標準成績 圖 5.老師在評分期間查看評分量表。

StudentSubmissions 已使用評量標準評分,因此會產生兩個新屬性:draftRubricGradesassignedRubricGrades,分別代表老師在草稿和指派評分狀態下選擇的分數和等級。

您可以使用現有的 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
        ).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))

draftRubricGradesassignedRubricGrades 包含:

  • 對應評分標準的 criterionId
  • 教師為每項準則指派的 points。這可能是來自所選等級,但老師也可能已覆寫這項資訊。
  • 為每個準則所選取的等級的 levelId。如果老師未選擇等級,但仍為評量標準指派點數,則不會顯示這個欄位。

這些清單只包含老師選取等級或設定分數的條件項目。舉例來說,如果老師選擇在評分期間只與一個標準互動,draftRubricGradesassignedRubricGrades 就只會有一個項目,即使評分標準包含多個標準。

刪除評分量表

您可以使用標準 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
        ).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
            ).execute()

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

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