Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Programming exercises: Add Artemis intelligence rewriting for problem statement #10156

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
51 commits
Select commit Hold shift + click to select a range
be1583a
Initial setup of new branch
cremertim Jan 16, 2025
8c467fa
initial setup finished
cremertim Jan 16, 2025
b06e720
alert Service
cremertim Jan 16, 2025
43e4e4e
add artemis intelligence dropdown for AI text editor actions
FelixTJDietrich Jan 16, 2025
8f45f69
Merge branch 'develop' into feature/communication/rephrasing-pipeline
cremertim Jan 16, 2025
e4c307a
remove currently test
cremertim Jan 16, 2025
a318d3f
Merge remote-tracking branch 'origin/feature/communication/rephrasing…
cremertim Jan 16, 2025
6875c4f
Added Felix Icon to resemble AI
cremertim Jan 16, 2025
ba2b5d1
Renamed everything to rewrite
cremertim Jan 16, 2025
c5b77a9
Updated comments and adressed changes from Felix
cremertim Jan 17, 2025
7e24015
fixed issues
cremertim Jan 17, 2025
fe6141e
fix some found issues directly
FelixTJDietrich Jan 17, 2025
e845b8d
fix too many arguments
FelixTJDietrich Jan 17, 2025
57b08c6
fix comment
FelixTJDietrich Jan 17, 2025
369e4b4
fix another comment
FelixTJDietrich Jan 17, 2025
e151990
Merge branch 'develop' into feature/communication/rephrasing-pipeline
FelixTJDietrich Jan 17, 2025
8ede345
reorganize translations and add artemis intelligence dropdown
FelixTJDietrich Jan 17, 2025
6ec2d01
changed to signal
cremertim Jan 17, 2025
06f5bd2
rename service and fix loading spinner and spamming
FelixTJDietrich Jan 17, 2025
f1c27a8
fix missed merge conflict
FelixTJDietrich Jan 17, 2025
446332f
merge faq rephrasing into current branch
FelixTJDietrich Jan 17, 2025
7418566
Fixed tests
cremertim Jan 17, 2025
23d0830
Prettier
cremertim Jan 17, 2025
3a7afa1
Merge remote-tracking branch 'origin/feature/communication/rephrasing…
FelixTJDietrich Jan 17, 2025
b745604
add artemis intelligence rewrite action to problem statement
FelixTJDietrich Jan 17, 2025
76fb2a1
add RewriteRequest
cremertim Jan 17, 2025
fbd97b2
Merge branch 'develop' into feature/communication/rephrasing-pipeline
cremertim Jan 20, 2025
d6ef320
fix double import
FelixTJDietrich Jan 20, 2025
4d562f6
Merge branch 'develop' into feature/communication/rephrasing-pipeline
cremertim Jan 20, 2025
7eb7409
Merge branch 'develop' into feature/communication/rephrasing-pipeline
cremertim Jan 21, 2025
aeeec63
Merge branch 'develop' into feature/communication/rephrasing-pipeline
cremertim Jan 21, 2025
9bd725b
Fixed client build
cremertim Jan 21, 2025
1fe0bac
Merge remote-tracking branch 'origin/feature/communication/rephrasing…
cremertim Jan 21, 2025
97a9f64
Rename TextRequestDTO
cremertim Jan 21, 2025
f4002b0
Include the @jsonInclude
cremertim Jan 21, 2025
10c89e8
Include the @jsonInclude for another one
cremertim Jan 21, 2025
ef89f62
Fix failing tests
cremertim Jan 21, 2025
cf5cae0
Merge branch 'develop' into feature/communication/rephrasing-pipeline
cremertim Jan 22, 2025
8a431b7
Merge branch 'develop' into feature/communication/rephrasing-pipeline
cremertim Jan 28, 2025
b3634eb
Merge branch 'feature/communication/rephrasing-pipeline' into feature…
FelixTJDietrich Jan 29, 2025
8484123
Rename RewritingResource
cremertim Jan 29, 2025
2daddff
Add random testcase for coverage
cremertim Jan 29, 2025
678b497
Merge branch 'feature/communication/rephrasing-pipeline' into feature…
FelixTJDietrich Jan 29, 2025
7c3251d
Merge branch 'develop' into feature/communication/rephrasing-pipeline
FelixTJDietrich Jan 29, 2025
ccb5fb6
remove unused translation
FelixTJDietrich Jan 29, 2025
f17f289
Merge branch 'feature/communication/rephrasing-pipeline' into feature…
FelixTJDietrich Jan 29, 2025
c76aa7c
Fix testcases
cremertim Jan 29, 2025
3cb8439
Merge remote-tracking branch 'origin/feature/programming-exercises/re…
cremertim Jan 29, 2025
efaaa21
Fix testcases
cremertim Jan 29, 2025
5a5a9d8
Fix testcases
cremertim Jan 29, 2025
f8e9c67
Merge branch 'develop' into feature/programming-exercises/rephrase-ac…
FelixTJDietrich Jan 30, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
<jhi-markdown-editor-monaco
class="overflow-hidden flex-grow-1"
[domainActions]="domainActions"
[artemisIntelligenceActions]="artemisIntelligenceActions()"
[initialEditorHeight]="initialEditorHeight"
[useDefaultMarkdownEditorOptions]="false"
[enableResize]="enableResize"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,23 @@
import { AfterViewInit, Component, EventEmitter, HostListener, Input, OnChanges, OnDestroy, Output, SimpleChanges, ViewChild, ViewEncapsulation, inject } from '@angular/core';
import {
AfterViewInit,
Component,
EventEmitter,
HostListener,
Input,
OnChanges,
OnDestroy,
OnInit,
Output,
SimpleChanges,
ViewChild,
ViewEncapsulation,
computed,
inject,
} from '@angular/core';
import { AlertService } from 'app/core/util/alert.service';
import { ProgrammingExerciseInstructionComponent } from 'app/exercises/programming/shared/instructions-render/programming-exercise-instruction.component';
import { Observable, Subject, Subscription, of, throwError } from 'rxjs';
import { catchError, map as rxMap, switchMap, tap } from 'rxjs/operators';
import { catchError, map, switchMap, tap } from 'rxjs/operators';
import { ProgrammingExerciseTestCase } from 'app/entities/programming/programming-exercise-test-case.model';
import { ProblemStatementAnalysis } from 'app/exercises/programming/manage/instructions-editor/analysis/programming-exercise-instruction-analysis.model';
import { Participation } from 'app/entities/participation/participation.model';
Expand All @@ -25,6 +40,13 @@ import { TranslateDirective } from 'app/shared/language/translate.directive';
import { NgbTooltip } from '@ng-bootstrap/ng-bootstrap';
import { ProgrammingExerciseInstructionAnalysisComponent } from './analysis/programming-exercise-instruction-analysis.component';
import { ArtemisTranslatePipe } from 'app/shared/pipes/artemis-translate.pipe';
import { RewriteAction } from 'app/shared/monaco-editor/model/actions/artemis-intelligence/rewrite.action';
import { PROFILE_IRIS } from 'app/app.constants';
import RewritingVariant from 'app/shared/monaco-editor/model/actions/artemis-intelligence/rewriting-variant';
import { ProfileService } from 'app/shared/layouts/profiles/profile.service';
import { ArtemisIntelligenceService } from 'app/shared/monaco-editor/model/actions/artemis-intelligence/artemis-intelligence.service';
import { toSignal } from '@angular/core/rxjs-interop';
import { ActivatedRoute } from '@angular/router';

@Component({
selector: 'jhi-programming-exercise-editable-instructions',
Expand All @@ -42,11 +64,14 @@ import { ArtemisTranslatePipe } from 'app/shared/pipes/artemis-translate.pipe';
ArtemisTranslatePipe,
],
})
export class ProgrammingExerciseEditableInstructionComponent implements AfterViewInit, OnChanges, OnDestroy {
export class ProgrammingExerciseEditableInstructionComponent implements AfterViewInit, OnChanges, OnDestroy, OnInit {
private activatedRoute = inject(ActivatedRoute);
private programmingExerciseService = inject(ProgrammingExerciseService);
private alertService = inject(AlertService);
private programmingExerciseParticipationService = inject(ProgrammingExerciseParticipationService);
private testCaseService = inject(ProgrammingExerciseGradingService);
private profileService = inject(ProfileService);
private artemisIntelligenceService = inject(ArtemisIntelligenceService);

participationValue: Participation;
programmingExercise: ProgrammingExercise;
Expand All @@ -57,6 +82,12 @@ export class ProgrammingExerciseEditableInstructionComponent implements AfterVie
testCaseAction = new TestCaseAction();
domainActions: TextEditorDomainAction[] = [new FormulaAction(), new TaskAction(), this.testCaseAction];

courseId: number;
irisEnabled = toSignal(this.profileService.getProfileInfo().pipe(map((profileInfo) => profileInfo.activeProfiles.includes(PROFILE_IRIS))), { initialValue: false });
artemisIntelligenceActions = computed(() =>
this.irisEnabled() ? [new RewriteAction(this.artemisIntelligenceService, RewritingVariant.PROBLEM_STATEMENT, this.courseId)] : [],
);

savingInstructions = false;
unsavedChangesValue = false;

Expand Down Expand Up @@ -117,6 +148,10 @@ export class ProgrammingExerciseEditableInstructionComponent implements AfterVie

protected readonly MarkdownEditorHeight = MarkdownEditorHeight;

ngOnInit() {
this.courseId = Number(this.activatedRoute.snapshot.paramMap.get('courseId'));
}

ngOnChanges(changes: SimpleChanges): void {
if (hasExerciseChanged(changes)) {
this.setupTestCaseSubscription();
Expand Down Expand Up @@ -236,9 +271,9 @@ export class ProgrammingExerciseEditableInstructionComponent implements AfterVie
loadTestCasesFromTemplateParticipationResult = (templateParticipationId: number): Observable<Array<string | undefined>> => {
// Fallback for exercises that don't have test cases yet.
return this.programmingExerciseParticipationService.getLatestResultWithFeedback(templateParticipationId).pipe(
rxMap((result) => (!result?.feedbacks ? throwError(() => new Error('no result available')) : result)),
map((result) => (!result?.feedbacks ? throwError(() => new Error('no result available')) : result)),
// use the text (legacy case) or the name of the provided test case attribute
rxMap(({ feedbacks }: Result) => feedbacks!.map((feedback) => feedback.text ?? feedback.testCase?.testName).sort()),
map(({ feedbacks }: Result) => feedbacks!.map((feedback) => feedback.text ?? feedback.testCase?.testName).sort()),
catchError(() => of([])),
);
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { ComponentFixture, TestBed, fakeAsync, flush, tick } from '@angular/core
import { TranslateService } from '@ngx-translate/core';
import { By } from '@angular/platform-browser';
import { ProgrammingExerciseService } from 'app/exercises/programming/manage/services/programming-exercise.service';
import { MockComponent, MockDirective, MockPipe } from 'ng-mocks';
import { MockComponent, MockDirective, MockPipe, MockProvider } from 'ng-mocks';
import { Subject, of, throwError } from 'rxjs';
import { DebugElement } from '@angular/core';
import { ArtemisTestModule } from '../../test.module';
Expand All @@ -28,6 +28,9 @@ import { HttpResponse } from '@angular/common/http';
import { AlertService } from 'app/core/util/alert.service';
import { MockAlertService } from '../../helpers/mocks/service/mock-alert.service';
import { MarkdownEditorMonacoComponent } from 'app/shared/markdown-editor/monaco/markdown-editor-monaco.component';
import { ActivatedRoute, convertToParamMap } from '@angular/router';
import { ProfileService } from 'app/shared/layouts/profiles/profile.service';
import { ProfileInfo } from '../../../../../main/webapp/app/shared/layouts/profiles/profile-info.model';

describe('ProgrammingExerciseEditableInstructionComponent', () => {
let comp: ProgrammingExerciseEditableInstructionComponent;
Expand All @@ -53,6 +56,17 @@ describe('ProgrammingExerciseEditableInstructionComponent', () => {
{ testName: 'test3', active: false },
];

const mockProfileInfo = { activeProfiles: ['iris'] } as ProfileInfo;

const route = {
snapshot: { paramMap: convertToParamMap({ courseId: '1' }) },
url: {
pipe: () => ({
subscribe: () => {},
}),
},
} as ActivatedRoute;

beforeEach(() => {
return TestBed.configureTestingModule({
imports: [ArtemisTestModule, MockDirective(NgbTooltip)],
Expand All @@ -69,6 +83,10 @@ describe('ProgrammingExerciseEditableInstructionComponent', () => {
{ provide: ParticipationWebsocketService, useClass: MockParticipationWebsocketService },
{ provide: TranslateService, useClass: MockTranslateService },
{ provide: AlertService, useClass: MockAlertService },
{ provide: ActivatedRoute, useValue: route },
MockProvider(ProfileService, {
getProfileInfo: () => of(mockProfileInfo),
}),
],
})
.compileComponents()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { Subject } from 'rxjs';
import { Params } from '@angular/router';
import { convertToParamMap, Params } from '@angular/router';

export class MockActivatedRouteWithSubjects {
private subject = new Subject<Params>();
params = this.subject;

snapshot = { paramMap: convertToParamMap({ courseId: '1' }) };
setSubject = (subject: Subject<Params>) => {
this.params = subject;
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ import { MockParticipationService } from '../../helpers/mocks/service/mock-parti
import { MockProgrammingExerciseService } from '../../helpers/mocks/service/mock-programming-exercise.service';
import { WebsocketService } from 'app/core/websocket/websocket.service';
import { MockWebsocketService } from '../../helpers/mocks/service/mock-websocket.service';
import { MockComponent, MockModule, MockPipe } from 'ng-mocks';
import { MockComponent, MockModule, MockPipe, MockProvider } from 'ng-mocks';
import { CodeEditorContainerComponent } from 'app/exercises/programming/shared/code-editor/container/code-editor-container.component';
import { IncludedInScoreBadgeComponent } from 'app/exercises/shared/exercise-headers/included-in-score-badge.component';
import { ProgrammingExerciseInstructorExerciseStatusComponent } from 'app/exercises/programming/manage/status/programming-exercise-instructor-exercise-status.component';
Expand All @@ -67,6 +67,8 @@ import { CodeEditorMonacoComponent } from 'app/exercises/programming/shared/code
import { MarkdownEditorMonacoComponent } from 'app/shared/markdown-editor/monaco/markdown-editor-monaco.component';
import { mockCodeEditorMonacoViewChildren } from '../../helpers/mocks/mock-instance.helper';
import { REPOSITORY } from 'app/exercises/programming/manage/code-editor/code-editor-instructor-base-container.component';
import { ProfileService } from 'app/shared/layouts/profiles/profile.service';
import { ProfileInfo } from 'app/shared/layouts/profiles/profile-info.model';

describe('CodeEditorInstructorIntegration', () => {
let comp: CodeEditorInstructorAndEditorContainerComponent;
Expand All @@ -90,6 +92,8 @@ describe('CodeEditorInstructorIntegration', () => {
let findWithParticipationsSubject: Subject<{ body: ProgrammingExercise }>;
let routeSubject: Subject<Params>;

const mockProfileInfo = { activeProfiles: ['iris'] } as ProfileInfo;

// Workaround for an error with MockComponent(). You can remove this once https://github.com/help-me-mom/ng-mocks/issues/8634 is resolved.
mockCodeEditorMonacoViewChildren();

Expand Down Expand Up @@ -138,6 +142,9 @@ describe('CodeEditorInstructorIntegration', () => {
{ provide: ProgrammingExerciseParticipationService, useClass: MockProgrammingExerciseParticipationService },
{ provide: ProgrammingExerciseService, useClass: MockProgrammingExerciseService },
{ provide: WebsocketService, useClass: MockWebsocketService },
MockProvider(ProfileService, {
getProfileInfo: () => of(mockProfileInfo),
}),
],
})
.compileComponents()
Expand Down
Loading