Skip to content

Commit

Permalink
feat(CRater): Switch from XML to JSON endpoints (#714)
Browse files Browse the repository at this point in the history
  • Loading branch information
geoffreykwan authored Aug 15, 2022
1 parent 30a003d commit c4c6b82
Show file tree
Hide file tree
Showing 12 changed files with 194 additions and 30 deletions.
96 changes: 96 additions & 0 deletions src/app/services/cRaterService.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import { CRaterService } from '../../assets/wise5/services/cRaterService';
import { ConfigService } from '../../assets/wise5/services/configService';
import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing';
import { UtilService } from '../../assets/wise5/services/utilService';
import { CRaterIdea } from '../../assets/wise5/components/dialogGuidance/CRaterIdea';
import { CRaterScore } from '../../assets/wise5/components/dialogGuidance/CRaterScore';
let service: CRaterService;
let configService: ConfigService;
let http: HttpTestingController;
Expand Down Expand Up @@ -31,6 +33,7 @@ describe('CRaterService', () => {
getMultipleAttemptCRaterFeedbackTextByScore();
getMultipleAttemptCRaterScoringRuleByScore();
makeCRaterVerifyRequest();
getDataFromResponse();
});

function makeCRaterScoringRequest() {
Expand Down Expand Up @@ -330,3 +333,96 @@ function makeCRaterVerifyRequest() {
});
});
}

function getDataFromResponse() {
describe('getDataFromResponse()', () => {
it('should get single score data from response', () => {
const score = 1;
const idea1Detected = true;
const response = {
responses: {
feedback: {
ideas: {
1: {
detected: idea1Detected
}
}
},
scores: {
raw_trim_round: score
}
}
};
const cRaterResponse = service.getCRaterResponse(response);
expect(cRaterResponse.score).toEqual(score);
expect(cRaterResponse.ideas).toEqual([new CRaterIdea('1', idea1Detected)]);
});

it('should get multiple scores data from response', () => {
const kiRaw = 2.2;
const kiRawTrimRound = 2;
const kiScoreRangeMax = 5;
const kiScoreRangeMin = 1;
const dciRaw = 1.1;
const dciRawTrimRound = 1;
const dciScoreRangeMax = 3;
const dciScoreRangeMin = 1;
const idea1Detected = true;
const idea2Detected = false;
const response = {
responses: {
feedback: {
ideas: {
1: {
detected: idea1Detected
},
2: {
detected: idea2Detected
}
}
},
trait_scores: {
ki: {
raw: kiRaw,
raw_trim_round: kiRawTrimRound,
score_range_max: kiScoreRangeMax,
score_range_min: kiScoreRangeMin
},
dci: {
raw: dciRaw,
raw_trim_round: dciRawTrimRound,
score_range_max: dciScoreRangeMax,
score_range_min: dciScoreRangeMin
}
}
}
};
const cRaterResponse = service.getCRaterResponse(response);
expect(cRaterResponse.scores).toEqual([
new CRaterScore('ki', kiRawTrimRound, kiRaw, kiScoreRangeMin, kiScoreRangeMax),
new CRaterScore('dci', dciRawTrimRound, dciRaw, dciScoreRangeMin, dciScoreRangeMax)
]);
expect(cRaterResponse.ideas).toEqual([
new CRaterIdea('1', idea1Detected),
new CRaterIdea('2', idea2Detected)
]);
});

it('should get data from response when there are no ideas', () => {
const score = 1;
const response = {
responses: {
feedback: {
ideas: {}
},
scores: {
raw_trim_round: score
}
}
};
const cRaterResponse = service.getCRaterResponse(response);
expect(cRaterResponse.score).toEqual(score);
expect(cRaterResponse.ideas).toEqual([]);
});
});
}
5 changes: 5 additions & 0 deletions src/assets/wise5/components/dialogGuidance/CRaterIdea.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,9 @@ export class CRaterIdea {
name: string;
detected: boolean;
characterOffsets: any[];

constructor(name: string, detected: boolean) {
this.name = name;
this.detected = detected;
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { CRaterResponse } from './CRaterResponse';
import { CRaterScore } from './CRaterScore';

const response = new CRaterResponse();
describe('CRaterResponse', () => {
Expand All @@ -23,7 +24,7 @@ function getDetectedIdeaNames() {
function getKIScore() {
describe('getKIScore()', () => {
it('should return the KI score', () => {
response.scores = [{ id: 'ki', score: 2, realNumberScore: 2.13 }];
response.scores = [new CRaterScore('ki', 2, 2.13, 1, 5)];
expect(response.getKIScore()).toEqual(2);
});
});
Expand All @@ -32,9 +33,9 @@ function getKIScore() {
function isNonScorable() {
describe('isNonScorable()', () => {
it('should return true for non-scorable item and false for scorable item', () => {
response.scores = [{ id: 'nonscorable', score: 1, realNumberScore: 1 }];
response.scores = [new CRaterScore('nonscorable', 1, 1, 1, 5)];
expect(response.isNonScorable()).toBeTruthy();
response.scores = [{ id: 'nonscorable', score: 0, realNumberScore: 0 }];
response.scores = [new CRaterScore('nonscorable', 0, 0, 1, 5)];
expect(response.isNonScorable()).toBeFalsy();
});
});
Expand Down
14 changes: 12 additions & 2 deletions src/assets/wise5/components/dialogGuidance/CRaterScore.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,21 @@
export class CRaterScore {
id: string;
score: number;
realNumberScore: number;
score: number;
scoreRangeMax: number;
scoreRangeMin: number;

constructor(id: string, score: number, realNumberScore: number) {
constructor(
id: string,
score: number,
realNumberScore: number,
scoreRangeMin: number,
scoreRangeMax: number
) {
this.id = id;
this.score = score;
this.realNumberScore = realNumberScore;
this.scoreRangeMin = scoreRangeMin;
this.scoreRangeMax = scoreRangeMax;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -201,9 +201,10 @@ function finalSubmit() {

function nonScorable() {
it('should return non-scorable rule when the item is not scorable', () => {
expectFeedback([], [{ id: 'nonscorable', score: 1, realNumberScore: 1 }], 'isNonScorable');
expectFeedback([], [new CRaterScore('nonscorable', 1, 1, 1, 5)], 'isNonScorable');
});
}

function expectFeedback(ideas: string[], scores: CRaterScore[], expectedFeedback: string) {
const rule = getFeedbackRule(ideas, scores);
expect(rule.feedback).toContain(expectedFeedback);
Expand All @@ -216,10 +217,7 @@ function getFeedbackRule(ideas: string[], scores: CRaterScore[]): FeedbackRule {
function createCRaterResponse(ideas: string[], scores: CRaterScore[]): CRaterResponse {
const response = new CRaterResponse();
response.ideas = ideas.map((idea) => {
const cRaterIdea = new CRaterIdea();
cRaterIdea.name = idea;
cRaterIdea.detected = true;
return cRaterIdea;
return new CRaterIdea(idea, true);
});
response.scores = scores;
return response;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ describe('DialogGuidanceStudentComponent', () => {

it('should create computer dialog response with multiple scores', () => {
const response = new CRaterResponse();
const scores = [new CRaterScore('ki', 5, 5.0), new CRaterScore('science', 4, 4.1)];
const scores = [new CRaterScore('ki', 5, 5.0, 1, 5), new CRaterScore('science', 4, 4.1, 1, 5)];
response.scores = scores;
const computerDialogResponse = component.createComputerDialogResponse(response);
expect((computerDialogResponse as ComputerDialogResponseMultipleScores).scores).toEqual(scores);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -209,8 +209,8 @@ export class DialogGuidanceStudentComponent extends ComponentStudent {
)
.pipe(timeout(this.cRaterTimeout))
.subscribe(
(response: CRaterResponse) => {
this.cRaterSuccessResponse(Object.assign(new CRaterResponse(), response));
(response: any) => {
this.cRaterSuccessResponse(this.CRaterService.getCRaterResponse(response));
},
() => {
this.cRaterErrorResponse();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -94,9 +94,9 @@ export class EditOpenResponseAdvancedComponent extends EditAdvancedComponentComp
verifyCRaterItemId(itemId: string): void {
this.cRaterItemIdIsValid = null;
this.isVerifyingCRaterItemId = true;
this.CRaterService.makeCRaterVerifyRequest(itemId).then((isValid) => {
this.CRaterService.makeCRaterVerifyRequest(itemId).then((response: any) => {
this.isVerifyingCRaterItemId = false;
this.cRaterItemIdIsValid = isValid;
this.cRaterItemIdIsValid = response.available;
});
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,16 @@ function createComponentStateAdditionalProcessing() {
spyOn(TestBed.inject(OpenResponseService), 'isCompletedV2').and.returnValue(true);
spyOn(component, 'isCRaterScoreOnSubmit').and.returnValue(true);
spyOn(TestBed.inject(CRaterService), 'makeCRaterScoringRequest').and.returnValue(
of({ score: 1 })
of({
responses: {
feedback: {
ideas: {}
},
scores: {
raw_trim_round: 1
}
}
})
);
component.isSubmit = true;
component.createComponentState('submit').then((componentState: any) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -358,8 +358,8 @@ export class OpenResponseStudent extends ComponentStudent {
)
.pipe(timeout(this.cRaterTimeout))
.subscribe(
(data: any) => {
this.cRaterSuccessResponse(data, componentState, deferred, dialogRef);
(response: any) => {
this.cRaterSuccessResponse(response, componentState, deferred, dialogRef);
},
() => {
this.cRaterErrorResponse(componentState, deferred, dialogRef);
Expand All @@ -378,28 +378,27 @@ export class OpenResponseStudent extends ComponentStudent {
deferred.resolve(componentState);
}

private cRaterSuccessResponse(data: any, componentState: any, deferred: any, dialogRef: any) {
let score = data.score;
let concepts = data.concepts;
if (data.scores != null) {
private cRaterSuccessResponse(response: any, componentState: any, deferred: any, dialogRef: any) {
const cRaterResponse = this.CRaterService.getCRaterResponse(response);
let score = cRaterResponse.score;
if (cRaterResponse.scores != null) {
const maxSoFarFunc = (accumulator, currentValue) => {
return Math.max(accumulator, currentValue.score);
};
score = data.scores.reduce(maxSoFarFunc, 0);
score = cRaterResponse.scores.reduce(maxSoFarFunc, 0);
}
if (score != null) {
this.processCRaterSuccessResponse(score, concepts, data, componentState);
this.processCRaterSuccessResponse(score, cRaterResponse, componentState);
}
dialogRef.close();
deferred.resolve(componentState);
}

private processCRaterSuccessResponse(score: any, concepts: any, data: any, componentState: any) {
private processCRaterSuccessResponse(score: any, data: any, componentState: any) {
let previousScore = null;
const autoScoreAnnotationData: any = {
value: score,
maxAutoScore: this.ProjectService.getMaxScoreForComponent(this.nodeId, this.componentId),
concepts: concepts,
autoGrader: 'cRater'
};
if (data.scores != null) {
Expand All @@ -410,7 +409,6 @@ export class OpenResponseStudent extends ComponentStudent {
}

let autoScoreAnnotation = this.createAutoScoreAnnotation(autoScoreAnnotationData);
let annotationGroupForScore = null;
const latestAnnotations = this.AnnotationService.getLatestComponentAnnotations(
this.nodeId,
this.componentId,
Expand Down Expand Up @@ -448,7 +446,6 @@ export class OpenResponseStudent extends ComponentStudent {
if (autoComment != null) {
const autoCommentAnnotationData: any = {};
autoCommentAnnotationData.value = autoComment;
autoCommentAnnotationData.concepts = concepts;
autoCommentAnnotationData.autoGrader = 'cRater';

const autoCommentAnnotation = this.createAutoCommentAnnotation(autoCommentAnnotationData);
Expand Down
48 changes: 48 additions & 0 deletions src/assets/wise5/services/cRaterService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ import { Injectable } from '@angular/core';
import { HttpClient, HttpParams } from '@angular/common/http';
import { ConfigService } from './configService';
import { Observable, of } from 'rxjs';
import { CRaterIdea } from '../components/dialogGuidance/CRaterIdea';
import { CRaterScore } from '../components/dialogGuidance/CRaterScore';
import { CRaterResponse } from '../components/dialogGuidance/CRaterResponse';

@Injectable()
export class CRaterService {
Expand Down Expand Up @@ -301,4 +304,49 @@ export class CRaterService {
return isAvailable;
});
}

public getCRaterResponse(response: any): CRaterResponse {
const cRaterResponse: CRaterResponse = new CRaterResponse();
if (this.isSingleScore(response)) {
cRaterResponse.score = this.getScore(response);
} else {
cRaterResponse.scores = this.getScores(response);
}
cRaterResponse.ideas = this.getIdeas(response);
return cRaterResponse;
}

private isSingleScore(response: any): boolean {
return response.responses.scores != null;
}

private getScore(response: any): number {
return response.responses.scores.raw_trim_round;
}

private getScores(response: any): CRaterScore[] {
const scores = [];
for (const key in response.responses.trait_scores) {
const value = response.responses.trait_scores[key];
scores.push(
new CRaterScore(
key,
value.raw_trim_round,
value.raw,
value.score_range_min,
value.score_range_max
)
);
}
return scores;
}

private getIdeas(response: any): CRaterIdea[] {
const ideas = [];
for (const key in response.responses.feedback.ideas) {
const value = response.responses.feedback.ideas[key];
ideas.push(new CRaterIdea(key, value.detected));
}
return ideas;
}
}
4 changes: 2 additions & 2 deletions src/messages.xlf
Original file line number Diff line number Diff line change
Expand Up @@ -14690,14 +14690,14 @@ If this problem continues, let your teacher know and move on to the next activit
<source>This will replace your existing recording. Is this OK?</source>
<context-group purpose="location">
<context context-type="sourcefile">src/assets/wise5/components/openResponse/open-response-student/open-response-student.component.ts</context>
<context context-type="linenumber">706</context>
<context context-type="linenumber">703</context>
</context-group>
</trans-unit>
<trans-unit id="8057349329324626950" datatype="html">
<source>Are you sure you want to delete your recording?</source>
<context-group purpose="location">
<context context-type="sourcefile">src/assets/wise5/components/openResponse/open-response-student/open-response-student.component.ts</context>
<context context-type="linenumber">750</context>
<context context-type="linenumber">747</context>
</context-group>
</trans-unit>
<trans-unit id="5623290610025495479" datatype="html">
Expand Down

0 comments on commit c4c6b82

Please sign in to comment.