Wprowadzenie do ocen cząstkowych

rubric to szablon, którego nauczyciele mogą używać podczas oceniania prac uczniów. Interfejs Classroom API umożliwia zarządzanie tymi ocenami cząstkowymi w imieniu nauczyciela, a także odczytywanie ocen cząstkowych w przesłanych przez uczniów pracach.

Widok kryteriów oceny w interfejsie Classroom Rysunek 1. Widok przykładowych kryteriów oceny w projekcie w Classroom.

Ten przewodnik wyjaśnia podstawowe pojęcia i funkcje interfejsu Rubrics API. Więcej informacji o ogólnej strukturze kryteriów oceny i sposobie oceniania za pomocą kryteriów oceny w interfejsie Classroom znajdziesz w tych artykułach w Centrum pomocy.

Wymagania wstępne

W tym przewodniku przyjęto założenie, że masz:

Autoryzowanie danych logowania w aplikacji na komputer

Aby uwierzytelnić się jako użytkownik i uzyskać dostęp do danych użytkownika w aplikacji, musisz utworzyć co najmniej 1 identyfikator klienta OAuth 2.0. Identyfikator klienta wskazuje konkretną aplikację na serwerach OAuth Google. Jeśli Twoja aplikacja działa na kilku platformach, musisz utworzyć osobny identyfikator klienta dla każdej z nich.

  1. W konsoli Google Cloud otwórz stronę Dane logowania.
  2. Kliknij Utwórz dane logowania > Identyfikator klienta OAuth.
  3. Kliknij Typ aplikacji > Aplikacja na komputer.
  4. W polu Nazwa wpisz nazwę danych logowania. Ta nazwa jest wyświetlana tylko w konsoli Google Cloud. Na przykład „Klient rubryk”.
  5. Kliknij Utwórz. Wyświetli się ekran utworzonego klienta OAuth z nowym identyfikatorem klienta i tajnym kluczem klienta.
  6. Kliknij Pobierz JSON, a potem OK. Nowo utworzone dane logowania pojawią się w sekcji Identyfikatory klienta OAuth 2.0.
  7. Zapisz pobrany plik JSON jako credentials.json i przenieś go do katalogu roboczego.
  8. Kliknij Utwórz dane logowania > Klucz interfejsu API i zanotuj klucz interfejsu API.

Więcej informacji znajdziesz w artykule Tworzenie danych logowania.

Konfigurowanie zakresów protokołu OAuth

W zależności od zakresów OAuth w projekcie może być konieczne skonfigurowanie dodatkowych zakresów.

  1. Otwórz ekran zgody OAuth.
  2. Kliknij Edytuj aplikację > Zapisz i kontynuuj, aby przejść do ekranu Zakresy.
  3. Kliknij Dodaj lub usuń zakresy.
  4. Jeśli nie masz jeszcze tych zakresów, dodaj je:
    • https://www.googleapis.com/auth/classroom.coursework.students
    • https://www.googleapis.com/auth/classroom.courses
  5. Następnie kliknij Aktualizuj > Zapisz i kontynuuj > Zapisz i kontynuuj > Powrót do panelu.

Więcej informacji znajdziesz w artykule Konfigurowanie ekranu zgody OAuth.

Zakres classroom.coursework.students umożliwia odczyt i zapis rubryk (wraz z dostępem do CourseWork), a zakres classroom.courses umożliwia odczyt i zapis kursów.

Zakresy wymagane w przypadku danej metody są wymienione w dokumentacji referencyjnej tej metody. Przykładem są courses.courseWork.rubrics.createzakresy autoryzacji. Wszystkie zakresy Classroom znajdziesz w sekcji Zakresy OAuth 2.0 dla interfejsów API Google.

Konfigurowanie próbki

W katalogu roboczym zainstaluj bibliotekę klienta Google dla Pythona:

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

Utwórz plik o nazwie main.py, który tworzy bibliotekę klienta i autoryzuje użytkownika, używając klucza interfejsu API zamiast 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)

Uruchom skrypt za pomocą polecenia python main.py. Powinien wyświetlić się monit o zalogowanie się i wyrażenie zgody na zakresy OAuth.

Utwórz zadanie

Kryteria oceny są powiązane z projektem lub CourseWork i mają znaczenie tylko w kontekście tego CourseWork. Kryteria oceny może tworzyć tylko projekt w chmurze Google, który utworzył element nadrzędny CourseWork. Na potrzeby tego przewodnika utwórz nowe CourseWork przypisanie ze skryptem.

Dodaj te boty do pokoju „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

Teraz zaktualizuj main.py, aby pobrać course_id utworzonej właśnie klasy testowej, utworzyć nowe przykładowe zadanie i pobrać coursework_id zadania:

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.

Zapisz course_idcoursework_id. Są one potrzebne w przypadku wszystkich operacji CRUD dotyczących kryteriów oceny.

W Classroom powinna być teraz dostępna próbka CourseWork.

Widok projektu w interfejsie Classroom Rysunek 2. Widok przykładowego projektu w Classroom.

Sprawdzanie, czy użytkownik spełnia wymagania

Tworzenie i aktualizowanie rubryk wymaga, aby zarówno użytkownik wysyłający żądanie, jak i właściciel odpowiedniego kursu mieli przypisaną licencję Google Workspace for Education Plus. Classroom obsługuje punkt końcowy uprawnień użytkownika, aby umożliwić deweloperom określanie funkcji, do których użytkownik ma dostęp.

Zaktualizuj i uruchom main.py, aby potwierdzić, że Twoje konto testowe ma dostęp do funkcji rubryk:

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

Tworzenie kryteriów oceny

Możesz teraz zacząć zarządzać kryteriami.

Kryteria oceny można utworzyć za pomocą wywołania CourseWorkcreate() zawierającego pełny obiekt kryteriów oceny, w którym pominięto właściwości identyfikatora kryteriów i poziomów (są one generowane podczas tworzenia).

Dodaj do pliku main.py tę funkcję:

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

Następnie zaktualizuj i uruchom main.py, aby utworzyć przykładowe kryteria oceny, używając identyfikatorów Course i CourseWork z wcześniejszego kroku:

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))

Uwagi na temat reprezentacji rubryki:

  • Kolejność kryteriów i poziomów jest odzwierciedlona w interfejsie Classroom.
  • Poziomy z punktacją (te z właściwością points) muszą być posortowane według punktów w kolejności rosnącej lub malejącej (nie mogą być uporządkowane losowo).
  • Nauczyciele mogą ponownie sortować kryteria i poziomy z oceną (ale nie poziomy bez oceny) w interfejsie, co zmienia ich kolejność w danych.

Więcej informacji o strukturze ocen cząstkowych znajdziesz w sekcji ograniczenia.

W interfejsie powinien być widoczny arkusz oceny przypisany do zadania.

Widok kryteriów oceny w interfejsie Classroom Rysunek 3. Widok przykładowych kryteriów oceny w projekcie w Classroom.

Odczytywanie oceny cząstkowej

Rubryki można odczytywać za pomocą standardowych metod list()get().

W projekcie może być tylko 1 kryteria oceny, więc wartość list() może wydawać się nieintuicyjna, ale jest przydatna, jeśli nie masz jeszcze identyfikatora kryteriów oceny. Jeśli z CourseWork nie są powiązane żadne kryteria oceny, list() odpowiedź jest pusta.

Dodaj do pliku main.py tę funkcję:

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

Zaktualizuj i uruchom main.py, aby pobrać dodane kryteria oceny:

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.

Zanotuj właściwość id w rubryce, aby użyć jej w dalszych krokach.

Get() działa dobrze, gdy masz identyfikator kryteriów oceny. Użycie usługi get() w funkcji może wyglądać tak:

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

Jeśli nie ma rubryki, ta implementacja zwraca błąd 404.

Aktualizowanie kryteriów oceny

Aktualizacje kryteriów oceny są przeprowadzane za pomocą wywołań patch(). Ze względu na złożoną strukturę kryteriów oceny aktualizacje muszą być przeprowadzane zgodnie ze wzorcem odczyt-modyfikacja-zapis, w którym zastępowana jest cała właściwość criteria.

Reguły aktualizacji są następujące:

  1. Kryteria lub poziomy dodane bez identyfikatora są traktowane jako dodatki.
  2. Kryteria lub poziomy, których wcześniej brakowało, są traktowane jako usunięte.
  3. Kryteria lub poziomy z istniejącym identyfikatorem, ale zmodyfikowanymi danymi są traktowane jako zmiany. Niezmienione właściwości pozostają bez zmian.
  4. Kryteria lub poziomy podane z nowymi lub nieznanymi identyfikatorami są traktowane jako błędy.
  5. Kolejność nowych kryteriów i poziomów jest traktowana jako nowa kolejność w interfejsie (z wyżej wymienionymi ograniczeniami).

Dodaj funkcję aktualizowania kryteriów oceny:

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

W tym przykładzie pole criteria jest przeznaczone do modyfikacji za pomocą elementu updateMask.

Następnie zmodyfikuj main.py, aby wprowadzić zmianę w każdej z wymienionych wyżej reguł aktualizacji:

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))

Zmiany powinny być teraz widoczne dla nauczyciela w Classroom.

Widok zaktualizowanych kryteriów oceny w interfejsie Classroom Rysunek 4. Widok zaktualizowanych kryteriów oceny.

Wyświetlanie przesłanych prac ocenionych za pomocą oceny cząstkowej

Obecnie interfejs API nie umożliwia oceniania przesłanych prac uczniów za pomocą oceny cząstkowej, ale możesz odczytywać oceny cząstkowe przesłanych prac, które zostały ocenione za pomocą oceny cząstkowej w interfejsie Classroom.

Jako uczeń w interfejsie Classroom wykonaj i oddaj przykładowy projekt. Następnie jako nauczyciel ręcznie oceń projekt, korzystając z kryteriów oceny.

Widok oceny według kryteriów oceny w interfejsie Classroom Rysunek 5. Widok kryteriów oceny dla nauczyciela podczas oceniania.

StudentSubmissions, które zostały ocenione za pomocą kryteriów oceny, mają 2 nowe właściwości: draftRubricGrades i assignedRubricGrades, które reprezentują punkty i poziomy wybrane przez nauczyciela odpowiednio w stanach oceny wersji roboczej i przypisanej.

Aby wyświetlić ocenione przesłane zadania, możesz użyć dotychczasowych metod studentSubmissions.get()studentSubmissions.list().

Dodaj do main.py tę funkcję, aby wyświetlić zadania przesłane przez uczniów:

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

Następnie zaktualizuj i uruchom polecenie main.py, aby wyświetlić oceny przesłanych prac.

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 zawierają:

  • criterionId odpowiednich kryteriów oceny cząstkowej.
  • points nauczyciel przypisany do każdego kryterium. Może to być poziom wybrany przez nauczyciela, ale może on też zastąpić to ustawienie.
  • levelId poziomu wybranego dla każdego kryterium. Jeśli nauczyciel nie wybrał poziomu, ale przypisał punkty za kryterium, to pole nie jest obecne.

Te listy zawierają tylko wpisy dotyczące kryteriów, w przypadku których nauczyciel wybrał poziom lub ustawił punkty. Jeśli na przykład nauczyciel zdecyduje się oceniać tylko według jednego kryterium, w sekcjach draftRubricGrades i assignedRubricGrades będzie tylko 1 element, nawet jeśli rubryka zawiera wiele kryteriów.

Usuwanie kryteriów oceny

Rubrykę można usunąć za pomocą standardowego żądania delete(). Poniższy kod zawiera przykładową funkcję, ale ponieważ ocenianie już się rozpoczęło, nie możesz usunąć bieżącej oceny cząstkowej:

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

Eksportowanie i importowanie kryteriów oceny

Rubryki można ręcznie eksportować do Arkuszy Google, aby nauczyciele mogli ich ponownie używać.

Oprócz określania kryteriów oceny w kodzie można tworzyć i aktualizować kryteria oceny z tych wyeksportowanych arkuszy, określając sourceSpreadsheetId w treści kryteriów oceny zamiast 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