rubric
to szablon, którego nauczyciele mogą używać podczas oceniania prac uczniów. Interfejs Classroom API umożliwia działanie w imieniu nauczyciela w celu zarządzania tymi kryteriami oceniania, a także odczytywanie ocen w przesłanych przez uczniów pracach.
Rysunek 1. Widok przykładowej oceny cząstkowej w projekcie w Classroom.
Ten przewodnik wyjaśnia podstawowe pojęcia i funkcje interfejsu Rubrics API. Więcej informacji o ogólnej strukturze rubryki i sposobie oceniania za pomocą rubryki w interfejsie Classroom znajdziesz w tych artykułach w Centrum pomocy.
Wymagania wstępne
W tym przewodniku przyjęto założenie, że masz:
- Python 3.8.6 lub nowszy
- Narzędzie do zarządzania pakietami pip
- Projekt Google Cloud.
- konto Google Workspace for Education z włączoną usługą Google Classroom i przypisaną licencją Google Workspace for Education Plus; Jeśli nie masz konta demonstracyjnego dewelopera, możesz poprosić o jego uaktualnienie.
- Testowe zajęcia z co najmniej 1 testowym kontem ucznia. Jeśli nie masz zajęć w Classroom, których możesz użyć do testowania, utwórz je w interfejsie i dodaj testowego ucznia.
Autoryzowanie danych logowania do 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.
- W konsoli Google Cloud otwórz stronę Dane logowania.
- Kliknij Utwórz dane logowania > Identyfikator klienta OAuth.
- Kliknij Typ aplikacji > Aplikacja na komputer.
- W polu Nazwa wpisz nazwę danych logowania. Ta nazwa jest wyświetlana tylko w konsoli Google Cloud. Na przykład „Klient rubryk”.
- Kliknij Utwórz. Wyświetli się ekran utworzonego klienta OAuth z nowym identyfikatorem klienta i tajnym kluczem klienta.
- Kliknij Pobierz JSON, a potem OK. Nowo utworzone dane logowania pojawią się w sekcji Identyfikatory klienta OAuth 2.0.
- Zapisz pobrany plik JSON jako
credentials.json
i przenieś go do katalogu roboczego. - 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.
- Otwórz ekran zgody OAuth.
- Kliknij Edytuj aplikację > Zapisz i kontynuuj, aby przejść do ekranu Zakresy.
- Kliknij Dodaj lub usuń zakresy.
- 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
- 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.create
zakresy 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 pojawić się monit o zalogowanie się i wyrażenie zgody na zakresy OAuth.
Utwórz zadanie
Rubryka jest powiązana z projektem lub CourseWork
i ma znaczenie tylko w kontekście tego CourseWork
. Kryteria oceny może utworzyć tylko projekt Google Cloud, który utworzył element nadrzędny CourseWork
. Na potrzeby tego przewodnika utwórz nowe CourseWork
przypisanie ze skryptem.
Dodać 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ć nowy przykładowy projekt i pobrać coursework_id
projektu:
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_id
i coursework_id
. Są one potrzebne do wszystkich operacji CRUD w przypadku rubryk.
W Classroom powinien być teraz dostępny przykładowy CourseWork
.
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, który umożliwia 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 oceny cząstkowej
Teraz możesz zacząć zarządzać kryteriami oceniania.
Ocenę cząstkową można utworzyć za pomocą wywołania CourseWork
z metodą create()
zawierającego pełny obiekt oceny cząstkowej, 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ładową rubrykę, 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))
Kilka uwag na temat reprezentacji ocen cząstkowych:
- 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.
Rysunek 3. Widok przykładowej oceny cząstkowej w projekcie w Classroom.
Odczytywanie oceny cząstkowej
Kryteria oceny można odczytać za pomocą standardowych metod list()
i get()
.
W zadaniu może być tylko 1 rubryka, więc wartość list()
może wydawać się nieintuicyjna, ale jest przydatna, jeśli nie masz jeszcze identyfikatora rubryki. Jeśli z CourseWork
nie jest powiązana żadna rubryka, odpowiedź list()
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ć dodaną ocenę cząstkową:
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 rubryki. 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 oceny cząstkowej
Aktualizacje rubryki są przeprowadzane za pomocą wywołań patch()
. Ze względu na złożoną strukturę rubryki 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:
- Kryteria lub poziomy dodane bez identyfikatora są traktowane jako dodatki.
- Kryteria lub poziomy, które zniknęły, są traktowane jako usunięte.
- Kryteria lub poziomy z istniejącym identyfikatorem, ale zmodyfikowanymi danymi są traktowane jako zmiany. Niezmienione właściwości pozostaną bez zmian.
- Kryteria lub poziomy podane z nowymi lub nieznanymi identyfikatorami są traktowane jako błędy.
- Kolejność nowych kryteriów i poziomów jest traktowana jako kolejność w nowym interfejsie (z wcześniej wspomnianymi ograniczeniami).
Dodaj funkcję aktualizowania oceny cząstkowej:
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 wskazane do modyfikacji za pomocą znaku 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.
Rysunek 4. Widok zaktualizowanej oceny cząstkowej.
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 za pomocą ocen cząstkowych.
Rysunek 5. Widok oceny cząstkowej dla nauczyciela podczas oceniania.
StudentSubmissions
, które zostały ocenione za pomocą rubryki, 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()
i 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 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))
draftRubricGrades
i assignedRubricGrades
zawierają:
criterionId
odpowiednich kryteriów oceny cząstkowej.points
ocena przyznana przez nauczyciela w przypadku 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 oceny cząstkowej
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 ocen cząstkowych
Oceny cząstkowe można ręcznie eksportować do Arkuszy Google, aby nauczyciele mogli ich ponownie używać.
Oprócz określania kryteriów oceny cząstkowej w kodzie można tworzyć i aktualizować oceny cząstkowe z tych wyeksportowanych arkuszy, określając sourceSpreadsheetId
w treści oceny cząstkowej 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