Skip to content

Commit b9c9cb3

Browse files
feat(AIChat): Connect to Open Response (#2170)
This is an addition of the AI Essay Assistant feature
1 parent d7456a0 commit b9c9cb3

File tree

10 files changed

+75
-28
lines changed

10 files changed

+75
-28
lines changed
Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
export class AiChatMessage {
22
content: string;
3+
hidden: boolean;
34
role: 'assistant' | 'system' | 'user';
45

5-
constructor(role: 'assistant' | 'system' | 'user', content: string) {
6+
constructor(role: 'assistant' | 'system' | 'user', content: string, hidden: boolean = false) {
67
this.content = content;
78
this.role = role;
9+
this.hidden = hidden;
810
}
911
}

src/assets/wise5/components/aiChat/ai-chat-bot-message/ai-chat-bot-message.component.spec.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { ComponentFixture, TestBed } from '@angular/core/testing';
22
import { AiChatBotMessageComponent } from './ai-chat-bot-message.component';
33
import { MatIconModule } from '@angular/material/icon';
44
import { ComputerAvatarService } from '../../../services/computerAvatarService';
5+
import { AiChatMessage } from '../AiChatMessage';
56

67
describe('AiChatBotMessageComponent', () => {
78
let component: AiChatBotMessageComponent;
@@ -15,7 +16,7 @@ describe('AiChatBotMessageComponent', () => {
1516
});
1617
fixture = TestBed.createComponent(AiChatBotMessageComponent);
1718
component = fixture.componentInstance;
18-
component.message = { content: 'Hello', role: 'assistant' };
19+
component.message = new AiChatMessage('assistant', 'Hello');
1920
component.computerAvatar = {
2021
id: 'robot1',
2122
name: 'Robot',

src/assets/wise5/components/aiChat/ai-chat-messages/ai-chat-messages.component.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<ng-container *ngFor="let message of messages">
22
<ai-chat-student-message
3-
*ngIf="message.role === 'user'"
3+
*ngIf="message.role === 'user' && !message.hidden"
44
class="ai-chat-message"
55
[message]="message"
66
[workgroupId]="workgroupId"

src/assets/wise5/components/aiChat/ai-chat-student-message/ai-chat-student-message.component.spec.ts

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,20 +3,24 @@ import { AiChatStudentMessageComponent } from './ai-chat-student-message.compone
33
import { ConfigService } from '../../../services/configService';
44
import { provideHttpClientTesting } from '@angular/common/http/testing';
55
import { provideHttpClient, withInterceptorsFromDi } from '@angular/common/http';
6+
import { AiChatMessage } from '../AiChatMessage';
67

78
describe('AiChatStudentMessageComponent', () => {
89
let component: AiChatStudentMessageComponent;
910
let fixture: ComponentFixture<AiChatStudentMessageComponent>;
1011

1112
beforeEach(() => {
1213
TestBed.configureTestingModule({
13-
declarations: [AiChatStudentMessageComponent],
14-
imports: [],
15-
providers: [ConfigService, provideHttpClient(withInterceptorsFromDi()), provideHttpClientTesting()]
16-
});
14+
declarations: [AiChatStudentMessageComponent],
15+
providers: [
16+
ConfigService,
17+
provideHttpClient(withInterceptorsFromDi()),
18+
provideHttpClientTesting()
19+
]
20+
});
1721
fixture = TestBed.createComponent(AiChatStudentMessageComponent);
1822
component = fixture.componentInstance;
19-
component.message = { content: 'Hello', role: 'user' };
23+
component.message = new AiChatMessage('user', 'Hello');
2024
fixture.detectChanges();
2125
});
2226

src/assets/wise5/components/aiChat/ai-chat-student/ai-chat-student.component.spec.ts

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,19 @@ import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
1616
import { MatSnackBarModule } from '@angular/material/snack-bar';
1717
import { ChatInputComponent } from '../../../common/chat-input/chat-input.component';
1818
import { provideHttpClient, withInterceptorsFromDi } from '@angular/common/http';
19+
import { TestbedHarnessEnvironment } from '@angular/cdk/testing/testbed';
20+
import { MatButtonHarness } from '@angular/material/button/testing';
21+
import { By } from '@angular/platform-browser';
1922

2023
describe('AiChatStudentComponent', () => {
2124
let component: AiChatStudentComponent;
2225
let fixture: ComponentFixture<AiChatStudentComponent>;
2326

2427
beforeEach(() => {
2528
TestBed.configureTestingModule({
26-
declarations: [AiChatStudentComponent],
27-
imports: [AiChatModule,
29+
declarations: [AiChatStudentComponent],
30+
imports: [
31+
AiChatModule,
2832
BrowserAnimationsModule,
2933
ChatInputComponent,
3034
ComponentHeaderComponent,
@@ -34,18 +38,29 @@ describe('AiChatStudentComponent', () => {
3438
MatFormFieldModule,
3539
MatInputModule,
3640
MatSnackBarModule,
37-
StudentTeacherCommonServicesModule],
38-
providers: [AiChatService, provideHttpClient(withInterceptorsFromDi()), provideHttpClientTesting()]
39-
});
41+
StudentTeacherCommonServicesModule
42+
],
43+
providers: [
44+
AiChatService,
45+
provideHttpClient(withInterceptorsFromDi()),
46+
provideHttpClientTesting()
47+
]
48+
});
4049
fixture = TestBed.createComponent(AiChatStudentComponent);
4150
component = fixture.componentInstance;
4251
component.component = new AiChatComponent({ id: 'component1', type: 'aiChat' }, 'node1');
52+
component.componentState = { studentData: { messages: [{ role: 'user' }] } };
4353
spyOn(component, 'isNotebookEnabled').and.returnValue(false);
4454
spyOn(TestBed.inject(ProjectService), 'getThemeSettings').and.returnValue({});
4555
fixture.detectChanges();
4656
});
4757

48-
it('should create', () => {
49-
expect(component).toBeTruthy();
58+
it('should not show response from a connected component', async () => {
59+
const studentMessages = fixture.debugElement.queryAll(By.css('ai-chat-student-message'));
60+
expect(studentMessages.length).toBe(1);
61+
component.processConnectedComponentState({ studentData: { response: 'test response' } });
62+
const loader = TestbedHarnessEnvironment.loader(fixture);
63+
await (await loader.getHarness(MatButtonHarness)).click();
64+
expect(studentMessages.length).toBe(1); // no new message should be added
5065
});
5166
});

src/assets/wise5/components/aiChat/ai-chat-student/ai-chat-student.component.ts

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,15 +19,16 @@ import { ComputerAvatarService } from '../../../services/computerAvatarService';
1919
import { StudentStatusService } from '../../../services/studentStatusService';
2020

2121
@Component({
22-
selector: 'ai-chat-student',
23-
templateUrl: './ai-chat-student.component.html',
24-
styleUrls: ['./ai-chat-student.component.scss'],
25-
standalone: false
22+
selector: 'ai-chat-student',
23+
templateUrl: './ai-chat-student.component.html',
24+
styleUrls: ['./ai-chat-student.component.scss'],
25+
standalone: false
2626
})
2727
export class AiChatStudentComponent extends ComponentStudent {
2828
component: AiChatComponent;
2929
protected computerAvatar: ComputerAvatar;
3030
protected computerAvatarSelectorVisible: boolean = false;
31+
private connectedComponentResponse: string;
3132
protected messages: AiChatMessage[] = [];
3233
protected studentResponse: string = '';
3334
protected submitEnabled: boolean = false;
@@ -82,6 +83,10 @@ export class AiChatStudentComponent extends ComponentStudent {
8283

8384
protected async submitStudentResponse(response: string): Promise<void> {
8485
this.waitingForComputerResponse = true;
86+
if (this.connectedComponentResponse != null) {
87+
this.messages.push(new AiChatMessage('user', this.connectedComponentResponse, true));
88+
this.connectedComponentResponse = null;
89+
}
8590
this.messages.push(new AiChatMessage('user', response));
8691
try {
8792
const response = await this.aiChatService.sendChatMessage(
@@ -119,6 +124,10 @@ export class AiChatStudentComponent extends ComponentStudent {
119124
return promise;
120125
}
121126

127+
processConnectedComponentState(componentState: any): void {
128+
this.connectedComponentResponse = componentState.studentData.response;
129+
}
130+
122131
initializeComputerAvatar: () => void;
123132
}
124133

src/assets/wise5/components/aiChat/edit-ai-chat-advanced/edit-ai-chat-advanced.component.html

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,12 @@
44
<mat-option *ngFor="let model of models" [value]="model">{{ model }}</mat-option>
55
</mat-select>
66
</mat-form-field>
7+
<edit-connected-components
8+
[nodeId]="component.nodeId"
9+
[componentId]="component.id"
10+
[allowedConnectedComponentTypes]="allowedConnectedComponentTypes"
11+
[componentContent]="component.content"
12+
[connectedComponents]="component.content.connectedComponents"
13+
(connectedComponentsChanged)="connectedComponentsChanged($event)"
14+
/>
715
<edit-component-json [component]="component"></edit-component-json>

src/assets/wise5/components/aiChat/edit-ai-chat-advanced/edit-ai-chat-advanced.component.spec.ts

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,20 @@ describe('EditAiChatAdvancedComponent', () => {
1515

1616
beforeEach(() => {
1717
TestBed.configureTestingModule({
18-
declarations: [EditAiChatAdvancedComponent],
19-
imports: [BrowserAnimationsModule,
18+
declarations: [EditAiChatAdvancedComponent],
19+
imports: [
20+
BrowserAnimationsModule,
2021
ComponentAuthoringModule,
2122
MatDialogModule,
22-
StudentTeacherCommonServicesModule],
23-
providers: [TeacherNodeService, TeacherProjectService, provideHttpClient(withInterceptorsFromDi()), provideHttpClientTesting()]
24-
});
23+
StudentTeacherCommonServicesModule
24+
],
25+
providers: [
26+
TeacherNodeService,
27+
TeacherProjectService,
28+
provideHttpClient(withInterceptorsFromDi()),
29+
provideHttpClientTesting()
30+
]
31+
});
2532
fixture = TestBed.createComponent(EditAiChatAdvancedComponent);
2633
component = fixture.componentInstance;
2734
component.nodeId = 'node1';

src/assets/wise5/components/aiChat/edit-ai-chat-advanced/edit-ai-chat-advanced.component.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,12 @@ import { EditAdvancedComponentComponent } from '../../../../../app/authoring-too
33
import { AiChatContent } from '../AiChatContent';
44

55
@Component({
6-
selector: 'edit-ai-chat-advanced',
7-
templateUrl: './edit-ai-chat-advanced.component.html',
8-
standalone: false
6+
selector: 'edit-ai-chat-advanced',
7+
templateUrl: './edit-ai-chat-advanced.component.html',
8+
standalone: false
99
})
1010
export class EditAiChatAdvancedComponent extends EditAdvancedComponentComponent {
11+
protected allowedConnectedComponentTypes = ['OpenResponse'];
1112
componentContent: AiChatContent;
1213
protected models: string[] = ['gpt-3.5-turbo', 'gpt-4'];
1314
}

src/messages.xlf

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15880,7 +15880,7 @@ Are you sure you want to proceed?</source>
1588015880
<source>An error occurred.</source>
1588115881
<context-group purpose="location">
1588215882
<context context-type="sourcefile">src/assets/wise5/components/aiChat/ai-chat-student/ai-chat-student.component.ts</context>
15883-
<context context-type="linenumber">96</context>
15883+
<context context-type="linenumber">101</context>
1588415884
</context-group>
1588515885
</trans-unit>
1588615886
<trans-unit id="1141886420788473147" datatype="html">

0 commit comments

Comments
 (0)