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

Enhancements: Requirements to Expand with AI #32

Merged
merged 10 commits into from
Feb 21, 2025
8 changes: 8 additions & 0 deletions .changeset/better-mugs-bet.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
"specif-ai": minor
---

- Update of requirements, user stories and tasks would remain on the same page without going back to listing page.
- Chat prompt update to be concise and not remove existing content from what user had provided.
- Prompt update to not talk about how the feature or entity would benefit the user.
- For PRDs, Screens and Personas which get generated while creating a project or updating the requirements would format to contain new lines before getting written to the file.
3 changes: 2 additions & 1 deletion backend/llm/prompts/02_update.jinja2
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@ FileContent: {{fileContent}}
Context:
{% include context %}

Based on the above context, update the existing requirement by incorporating the client's requests and the information from the provided file content.
Based on the above context, update the existing requirement by incorporating the client's requests and the information from the provided file content. Strictly don't eliminate the content given by the client. Instead groom and expand it.
Keep the responses very concise and to the point.

Output Structure should be a valid JSON: Here is the sample Structure:
{
Expand Down
1 change: 1 addition & 0 deletions backend/llm/prompts/chat/update_requirement.jinja2
Original file line number Diff line number Diff line change
Expand Up @@ -50,5 +50,6 @@ Strictly Prohibited:
- NO MENTION OF SPECIFIC PROGRAMMING LANGUAGES, FRAMEWORKS, LIBRARIES, OR TOOLS
- NO ARCHITECTURAL PATTERNS OR API SPECIFICATIONS
- NO DATABASE DESIGNS OR TECHNICAL TERMINOLOGY
- DO NOT MENTION HOW THIS WOULD BE HELPFUL TO THE USER
- NO STEP-BY-STEP TECHNICAL INSTRUCTIONS
- NO MARKDOWN FORMATTING (e.g., no #, ##, *, -, ````, etc.)
9 changes: 8 additions & 1 deletion ui/src/app/constants/app.constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -159,4 +159,11 @@ export const APP_MESSAGES = {

export const TOOLTIP_CONTENT = {
IMPORT_FROM_CODE_BUTTON: "Import from Code",
}
}

export const PRD_HEADINGS = {
SCREENS: 'Screens: ',
PERSONAS: 'Personas: ',
SCREENS_FORMATTED: '\n\nScreens:\n',
PERSONAS_FORMATTED: '\n\nPersonas:\n',
}
37 changes: 35 additions & 2 deletions ui/src/app/pages/edit-solution/edit-solution.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ import { ConfirmationDialogComponent } from '../../components/confirmation-dialo
import {
CONFIRMATION_DIALOG,
ERROR_MESSAGES,
PRD_HEADINGS,
TOASTER_MESSAGES,
} from '../../constants/app.constants';
import { ToasterService } from 'src/app/services/toaster/toaster.service';
Expand Down Expand Up @@ -146,6 +147,13 @@ export class EditSolutionComponent {
};
this.featureService.updateRequirement(body).subscribe(
(data) => {
data.updated.requirement = data.updated.requirement.replace(
PRD_HEADINGS.SCREENS,
PRD_HEADINGS.SCREENS_FORMATTED,
).replace(
PRD_HEADINGS.PERSONAS,
PRD_HEADINGS.PERSONAS_FORMATTED,
);
this.store.dispatch(
new UpdateFile(this.absoluteFilePath, {
requirement: data.updated.requirement,
Expand All @@ -155,7 +163,16 @@ export class EditSolutionComponent {
}),
);
this.allowFreeRedirection = true;
this.navigateBackToDocumentList(this.initialData);
this.store.dispatch(new ReadFile(`${this.folderName}/${this.fileName}`));
this.selectedFileContent$.subscribe((res: any) => {
this.oldContent = res.requirement;
this.requirementForm.patchValue({
title: res.title,
content: res.requirement,
epicticketid: res.epicTicketId,
});
this.chatHistory = res.chatHistory || [];
});
this.toastService.showSuccess(
TOASTER_MESSAGES.ENTITY.UPDATE.SUCCESS(
body.addReqtType,
Expand Down Expand Up @@ -183,7 +200,16 @@ export class EditSolutionComponent {
}),
);
this.allowFreeRedirection = true;
this.navigateBackToDocumentList(this.initialData);
this.store.dispatch(new ReadFile(`${this.folderName}/${this.fileName}`));
this.selectedFileContent$.subscribe((res: any) => {
this.oldContent = res.requirement;
this.requirementForm.patchValue({
title: res.title,
content: res.requirement,
epicticketid: res.epicTicketId,
});
this.chatHistory = res.chatHistory || [];
});
this.toastService.showSuccess(
TOASTER_MESSAGES.ENTITY.UPDATE.SUCCESS(
this.folderName,
Expand Down Expand Up @@ -224,6 +250,13 @@ export class EditSolutionComponent {
};
this.featureService.addRequirement(body).subscribe(
(data) => {
data.LLMreqt.requirement.replace(
PRD_HEADINGS.SCREENS,
PRD_HEADINGS.SCREENS_FORMATTED,
).replace(
PRD_HEADINGS.PERSONAS,
PRD_HEADINGS.PERSONAS_FORMATTED,
);
this.store.dispatch(
new CreateFile(`${this.folderName}`, {
requirement: data.LLMreqt.requirement,
Expand Down
29 changes: 27 additions & 2 deletions ui/src/app/pages/edit-user-stories/edit-user-stories.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ import {
import { ToasterService } from 'src/app/services/toaster/toaster.service';
import { ArchiveUserStory } from '../../store/user-stories/user-stories.actions';
import { ConfirmationDialogComponent } from 'src/app/components/confirmation-dialog/confirmation-dialog.component';
import { ReadFile } from 'src/app/store/projects/projects.actions';

@Component({
selector: 'app-edit-user-stories',
Expand Down Expand Up @@ -95,6 +96,9 @@ export class EditUserStoriesComponent implements OnDestroy {
selectedPRD: any = {};
allowFreeRedirection: boolean = false;
readonly dialog = inject(MatDialog);
selectedFileContent$ = this.store.select(
ProjectsState.getSelectedFileContent,
);
readonly regex = /\-feature.json$/;

constructor(
Expand Down Expand Up @@ -144,6 +148,11 @@ export class EditUserStoriesComponent implements OnDestroy {
}

updateUserStory() {
const findUserStory = (res: any, id: string) => {
let result = res.features.find((feature: any) => feature.id === id.toUpperCase());
return result;
}

if (
this.userStoryForm.getRawValue().expandAI ||
this.uploadedFileContent.length > 0
Expand Down Expand Up @@ -184,7 +193,15 @@ export class EditUserStoriesComponent implements OnDestroy {
}),
);
this.allowFreeRedirection = true;
this.navigateBackToUserStories();
this.store.dispatch(new ReadFile(`${this.folderName}/${this.fileName}`));
this.selectedFileContent$.subscribe((res: any) => {
let updatedDescription = findUserStory(res, this.data.id).description
this.userStoryForm.patchValue({
description: updatedDescription
});
this.description = res.requirement;
this.chatHistory = res.chatHistory || [];
});
this.toasterService.showSuccess(
TOASTER_MESSAGES.ENTITY.UPDATE.SUCCESS(
this.entityType,
Expand Down Expand Up @@ -215,7 +232,15 @@ export class EditUserStoriesComponent implements OnDestroy {
}),
);
this.allowFreeRedirection = true;
this.navigateBackToUserStories();
this.store.dispatch(new ReadFile(`${this.folderName}/${this.fileName}`));
this.selectedFileContent$.subscribe((res: any) => {
let updatedDescription = findUserStory(res, this.data.id).description
this.userStoryForm.patchValue({
description: updatedDescription
});
this.description = res.requirement;
this.chatHistory = res.chatHistory || [];
});
this.toasterService.showSuccess(
TOASTER_MESSAGES.ENTITY.UPDATE.SUCCESS(
this.entityType,
Expand Down
3 changes: 0 additions & 3 deletions ui/src/app/pages/tasks/add-task/add-task.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -246,12 +246,10 @@ export class AddTaskComponent implements OnDestroy {
subTaskTicketId: this.existingTask.subTaskTicketId,
},
`${this.selectedProject}/${this.config.folderName}/${newFileName}`,
true,
),
);
this.taskForm.markAsUntouched();
this.taskForm.markAsPristine();
this.navigateBackToTasks();
this.toastService.showSuccess(
TOASTER_MESSAGES.ENTITY.UPDATE.SUCCESS(
this.entityType,
Expand Down Expand Up @@ -417,7 +415,6 @@ ${chat.assistant}`,
);
this.taskForm.markAsUntouched();
this.taskForm.markAsPristine();
this.navigateBackToTasks();
this.toastService.showSuccess(
TOASTER_MESSAGES.ENTITY.UPDATE.SUCCESS(this.entityType, id),
);
Expand Down
5 changes: 4 additions & 1 deletion ui/src/app/store/projects/projects.state.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import { Router } from '@angular/router';
import { IList } from '../../model/interfaces/IList';
import { firstValueFrom } from 'rxjs';
import { ToasterService } from 'src/app/services/toaster/toaster.service';
import { BP_FILE_KEYS } from 'src/app/constants/app.constants';
import { BP_FILE_KEYS, PRD_HEADINGS } from 'src/app/constants/app.constants';
import { RequirementTypeEnum } from 'src/app/model/enum/requirement-type.enum';

export class ProjectStateModel {
Expand Down Expand Up @@ -160,6 +160,9 @@ export class ProjectsState {
this.generateFiles(brd, projectName, 'BRD'),
);
response.prd?.forEach((prd) => {
prd['requirement'] = prd['requirement']
.replace(PRD_HEADINGS.SCREENS, PRD_HEADINGS.SCREENS_FORMATTED)
.replace(PRD_HEADINGS.PERSONAS, PRD_HEADINGS.PERSONAS_FORMATTED);
this.generateFiles(prd, projectName, 'PRD');
this.generatePRDFeatureFiles(projectName, 'PRD', prd['id']);
});
Expand Down