Una rubric
è un modello che gli insegnanti possono utilizzare per valutare i compiti degli studenti. L'API Classroom ti consente di agire per conto dell'insegnante per gestire queste rubriche, nonché leggere i voti delle rubriche negli elaborati degli studenti.
Figura 1. Visualizzazione di una griglia di esempio in un compito di Classroom.
Questa guida spiega i concetti e le funzionalità di base dell'API Rubrics. Consulta questi articoli del Centro assistenza per scoprire la struttura generale di una rubrica e come viene eseguita la valutazione con rubrica nell'interfaccia utente di Classroom.
Prerequisiti
Questa guida presuppone che tu disponga di quanto segue:
- Python 3.8.6 o versioni successive
- Lo strumento di gestione pacchetti pip
- Un progetto Google Cloud.
- Un account Google Workspace for Education con Google Classroom abilitato e una licenza Google Workspace for Education Plus assegnata. Se non ne hai uno, puoi richiedere un account demo sviluppatore di livello superiore.
- Un corso di prova con almeno un account studente di prova. Se non hai un corso Classroom che puoi utilizzare per i test, creane uno nell'interfaccia utente e aggiungi uno studente di prova.
Autorizzare le credenziali per un'applicazione desktop
Per eseguire l'autenticazione come utente finale e accedere ai dati utente nella tua app, devi creare uno o più ID client OAuth 2.0. L'ID client viene utilizzato per identificare una singola app nei server OAuth di Google. Se l'app viene eseguita su più piattaforme, devi creare un ID client separato per ciascuna piattaforma.
- Vai alla pagina delle credenziali di Google Cloud nella console Google Cloud.
- Fai clic su Crea credenziali > ID client OAuth.
- Fai clic su Tipo di applicazione > App per computer.
- Nel campo Nome, digita un nome per la credenziale. Questo nome viene visualizzato solo nella console Google Cloud. Ad esempio, "Rubrics client".
- Fai clic su Crea. Viene visualizzata la schermata del client OAuth creato, che mostra il nuovo ID client e il nuovo client secret.
- Fai clic su Scarica JSON e poi su Ok. La credenziale appena creata viene visualizzata in ID client OAuth 2.0.
- Salva il file JSON scaricato come
credentials.json
e spostalo nella directory di lavoro. - Fai clic su Crea credenziali > Chiave API e annota la chiave API.
Per scoprire di più, consulta Creare le credenziali di accesso.
Configura gli ambiti OAuth
A seconda degli ambiti OAuth esistenti del progetto, potrebbe essere necessario configurare ambiti aggiuntivi.
- Vai alla schermata per il consenso OAuth.
- Fai clic su Modifica app > Salva e continua per accedere alla schermata Ambiti.
- Fai clic su Aggiungi o rimuovi ambiti.
- Aggiungi i seguenti ambiti se non li hai già:
https://www.googleapis.com/auth/classroom.coursework.students
https://www.googleapis.com/auth/classroom.courses
- Quindi, fai clic su Aggiorna > Salva e continua > Salva e continua > Torna alla dashboard.
Per saperne di più, consulta Configurare la schermata per il consenso OAuth.
L'ambito classroom.coursework.students
consente l'accesso in lettura e scrittura alle rubriche (insieme all'accesso a CourseWork
), mentre l'ambito classroom.courses
consente la lettura e la scrittura dei corsi.
Gli ambiti richiesti per un determinato metodo sono elencati nella documentazione di riferimento
per il metodo. Vedi gli ambiti di autorizzazione di courses.courseWork.rubrics.create
come esempio. Puoi visualizzare tutti gli ambiti di Classroom in Ambiti OAuth 2.0 per le API di Google.
Configura il campione
Nella directory di lavoro, installa la libreria client Google per Python:
pip install --upgrade google-api-python-client google-auth-httplib2 google-auth-oauthlib
Crea un file denominato main.py
che crea la libreria client e autorizza l'utente utilizzando la tua chiave API al posto di 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)
Esegui lo script utilizzando python main.py
. Ti verrà chiesto di accedere e
di acconsentire agli ambiti OAuth.
Crea un'assegnazione
Una rubrica è associata a un compito o a un CourseWork
ed è significativa solo nel contesto di questo CourseWork
. Le rubriche possono essere create solo dal
progetto Google Cloud che ha creato l'elemento CourseWork
padre. Ai fini di questa guida, crea un nuovo compito CourseWork
con uno script.
Aggiungi il seguente codice a 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
Ora aggiorna main.py
per recuperare course_id
della classe di test che hai appena
creato, crea un nuovo compito di esempio e recupera coursework_id
del compito:
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.
Salva course_id
e coursework_id
. Questi sono necessari per tutte le operazioni CRUD
delle rubriche.
Ora dovresti avere un esempio di CourseWork
in Classroom.
Figura 2. Visualizzazione di un compito di esempio in Classroom.
Verificare l'idoneità dell'utente
La creazione e l'aggiornamento delle rubriche richiedono che sia l'utente che effettua la richiesta sia il proprietario del corso corrispondente dispongano di una licenza Google Workspace for Education Plus. Classroom supporta un endpoint di idoneità utente per consentire agli sviluppatori di determinare le funzionalità a cui un utente ha accesso.
Aggiorna ed esegui main.py
per verificare che il tuo account di test abbia accesso alla
funzionalità delle rubriche:
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.')
Creare una griglia
Ora puoi iniziare a gestire le rubriche.
È possibile creare una rubrica su un CourseWork
con una chiamata create()
contenente
l'oggetto rubrica completo, in cui le proprietà ID per i criteri e i livelli sono
omesse (vengono generate al momento della creazione).
Aggiungi la seguente funzione a 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
Poi aggiorna ed esegui main.py
per creare la rubrica di esempio, utilizzando gli ID Course
e CourseWork
di prima:
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))
Alcuni punti sulla rappresentazione della griglia di valutazione:
- L'ordine dei criteri e dei livelli si riflette nella UI di Classroom.
- I livelli con punteggio (quelli con la proprietà
points
) devono essere ordinati per punti in ordine crescente o decrescente (non possono essere ordinati in modo casuale). - Gli insegnanti possono riordinare i criteri e i livelli con punteggio (ma non quelli senza punteggio) nell'interfaccia utente e questo modifica il loro ordine nei dati.
Per ulteriori avvertenze sulla struttura delle rubriche, consulta la sezione Limitazioni.
Tornando alla UI, dovresti vedere la rubrica nell'attività.
Figura 3. Visualizzazione di una griglia di esempio in un compito di Classroom.
Leggere una griglia
Le rubriche possono essere lette con i metodi standard list()
e get()
.
In un compito può essere presente al massimo un criterio, quindi list()
potrebbe sembrare
poco intuitivo, ma è utile se non hai già l'ID del criterio. Se non
è associata alcuna rubrica a un CourseWork
, la risposta list()
è vuota.
Aggiungi la seguente funzione a 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
Aggiorna ed esegui main.py
per recuperare la griglia che hai aggiunto:
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.
Prendi nota della proprietà id
nella rubrica per i passaggi successivi.
Get()
funziona bene quando hai l'ID rubrica. L'utilizzo di get()
nella funzione
potrebbe avere il seguente aspetto:
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
Questa implementazione restituisce un errore 404 se non è presente alcun criterio.
Aggiornare una griglia
Gli aggiornamenti a una rubrica vengono eseguiti con chiamate patch()
. A causa della complessa
struttura di una rubrica, gli aggiornamenti devono essere eseguiti con un pattern di lettura-modifica-scrittura,
in cui viene sostituita l'intera proprietà criteria
.
Le regole di aggiornamento sono le seguenti:
- I criteri o i livelli aggiunti senza un ID sono considerati aggiunte.
- I criteri o i livelli mancanti rispetto a prima vengono considerati eliminazioni.
- I criteri o i livelli con un ID esistente ma dati modificati sono considerati modifiche. Le proprietà non modificate vengono lasciate invariate.
- I criteri o i livelli forniti con ID nuovi o sconosciuti sono considerati errori.
- L'ordine dei nuovi criteri e livelli viene considerato il nuovo ordine dell'interfaccia utente (con le limitazioni sopra menzionate).
Aggiungi una funzione per aggiornare una griglia:
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
In questo esempio, il campo criteria
è specificato per la modifica con un
updateMask
.
Quindi, modifica main.py
per apportare una modifica a ciascuna delle regole di aggiornamento
menzionate in precedenza:
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))
Le modifiche ora dovrebbero essere visibili all'insegnante in Classroom.
Figura 4. Visualizzazione della griglia aggiornata.
Visualizzare i contenuti inviati valutati con una griglia
Per il momento, gli invii degli studenti non possono essere valutati con una griglia dall'API, ma puoi leggere i voti della griglia per gli invii che sono stati valutati con una griglia nell'interfaccia utente di Classroom.
In qualità di studente nell'interfaccia utente di Classroom, completa e consegna il compito di esempio. Quindi, in qualità di insegnante, valuta manualmente il compito utilizzando la griglia.
Figura 5. Visualizzazione della griglia lato insegnante durante la valutazione.
StudentSubmissions
valutati con una rubrica hanno due nuove
proprietà: draftRubricGrades
e assignedRubricGrades
, che rappresentano i
punti e i livelli scelti dall'insegnante durante gli stati di valutazione bozza e assegnata
rispettivamente.
Puoi utilizzare i metodi esistenti studentSubmissions.get()
e
studentSubmissions.list()
per visualizzare i contenuti inviati con voto.
Aggiungi la seguente funzione a main.py
per elencare i contenuti inviati dagli studenti:
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
Quindi aggiorna ed esegui main.py
per visualizzare i voti dei compiti inviati.
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
e assignedRubricGrades
contengono:
- Il
criterionId
dei criteri della griglia corrispondenti. points
l'insegnante assegnato per ciascun criterio. Potrebbe essere il livello selezionato, ma l'insegnante potrebbe anche averlo sovrascritto.- Il
levelId
del livello scelto per ciascun criterio. Se l'insegnante non ha scelto un livello, ma ha comunque assegnato punti per il criterio, questo campo non è presente.
Questi elenchi contengono solo voci per i criteri in cui un insegnante ha selezionato un livello o impostato punti. Ad esempio, se un insegnante sceglie di interagire solo con un criterio durante l'assegnazione del voto, draftRubricGrades
e assignedRubricGrades
avranno un solo elemento, anche se la rubrica ha molti criteri.
Eliminare una griglia
Una rubrica può essere eliminata con una richiesta standard delete()
. Il seguente codice
mostra una funzione di esempio per completezza, ma poiché la valutazione è già
iniziata, non puoi eliminare la griglia corrente:
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
Esportare e importare rubriche
Le griglie possono essere esportate manualmente in Fogli Google per essere riutilizzate dagli insegnanti.
Oltre a specificare i criteri della griglia di valutazione nel codice, è possibile creare e
aggiornare le griglie di valutazione da questi fogli esportati specificando
sourceSpreadsheetId
nel corpo di una griglia di valutazione anziché 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