diff --git a/backend/src/build-system/hanlder-manager.ts b/backend/src/build-system/hanlder-manager.ts index 67b45dcd..ef6e14ee 100644 --- a/backend/src/build-system/hanlder-manager.ts +++ b/backend/src/build-system/hanlder-manager.ts @@ -1,5 +1,6 @@ import { ProjectInitHandler } from './node/project-init'; import { BuildHandler } from './types'; +import { PRDHandler } from './node/product_requirements_document/prd'; export class BuildHandlerManager { private static instance: BuildHandlerManager; @@ -10,7 +11,10 @@ export class BuildHandlerManager { } private registerBuiltInHandlers() { - const builtInHandlers: BuildHandler[] = [new ProjectInitHandler()]; + const builtInHandlers: BuildHandler[] = [ + new ProjectInitHandler(), + new PRDHandler(), + ]; for (const handler of builtInHandlers) { this.handlers.set(handler.id, handler); diff --git a/backend/src/build-system/node/product_requirements_document/prd.ts b/backend/src/build-system/node/product_requirements_document/prd.ts new file mode 100644 index 00000000..a67e7f0d --- /dev/null +++ b/backend/src/build-system/node/product_requirements_document/prd.ts @@ -0,0 +1,58 @@ +import { BuildHandler, BuildResult } from 'src/build-system/types'; +import { BuilderContext } from 'src/build-system/context'; +import { prompts } from './prompt/prompt'; +import { ModelProvider } from 'src/common/model-provider'; +import { StreamStatus } from 'src/chat/chat.model'; +import * as fs from 'fs'; +import * as path from 'path'; + +export class PRDHandler implements BuildHandler { + readonly id = 'op:PRD::STATE:GENERATE'; + + async run(context: BuilderContext): Promise { + console.log('Generating PRD...'); + + // Extract project data from the context + const projectName = + context.getData('projectName') || 'Default Project Name'; + const description = context.getData('description') || 'Default Description'; + const platform = context.getData('platform') || 'Default Platform'; + + // Generate the prompt dynamically + const prompt = prompts.generatePRDPrompt( + projectName, + description, + platform, + ); + + // Send the prompt to the LLM server and process the response + const prdContent = await this.generatePRDFromLLM(prompt); + + // Save the PRD content to context for further use + context.setData('prdDocument', prdContent); + + return { + success: true, + data: prdContent, + }; + } + + private async generatePRDFromLLM(prompt: string): Promise { + const modelProvider = ModelProvider.getInstance(); + + const model = 'gpt-3.5-turbo'; + + // Call the chat method with the model specified + const chatStream = modelProvider.chat( + { + content: prompt, + }, + model, + ); // Pass the model here + + const prdContent = modelProvider.chunkSync(chatStream); + + console.log('Received full PRD content from LLM server.'); + return prdContent; + } +} diff --git a/backend/src/build-system/node/product_requirements_document/prompt/prompt.ts b/backend/src/build-system/node/product_requirements_document/prompt/prompt.ts new file mode 100644 index 00000000..848a8125 --- /dev/null +++ b/backend/src/build-system/node/product_requirements_document/prompt/prompt.ts @@ -0,0 +1,72 @@ +// Define and export the system prompts object + +export const prompts = { + generatePRDPrompt: ( + projectName: string, + description: string, + platform: string, + ): string => { + return `You are an expert Product Manager. Your job is to analyze and expand upon the details provided, generating a Full Product Requirement Document (PRD) based on the following inputs: + - Project name: ${projectName} + - Description: ${description} + - Platform: ${platform} + + Follow these guidelines to ensure clarity, thoroughness, and usability in the PRD, which will be directly utilized in development. + ### Instructions and Rules: + + 1, Your need to analysis the requirement for the project and covered all the things you can think about. + 2, You should focus on core features for the project + 3, ask yourself: + - what are all expect features require for a {project name} and {Description}? + - what are the user stories for the feature? + - what are the details description for those features? + - Am I cover all expect features ? if not then add new feature. + - Are those covered all user expected features ? if not then add new feature. + - what are the target audience for the project? Is all the features meet their expectation? if not then add new feature. + - Ask your self what are the function requirement and none functional requirement for those features? + - Are all features could be agree by others in the team? including product manager, developer.... + + ### PRD Structure: + + Start with the following structure. Do not include sections for Milestones, Deliverables, or Technical Requirements. + + --- + +### Product Requirement Document + +#### 1. Project Overview + - **Project Name**: + - **Description**: Provide a brief overview of the project’s objective and purpose. + - **Platform**: Indicate the platform(s) (e.g., Web, Mobile). + +#### 2. Goals and Objectives + - Define the primary goals and purpose of the project. + - Describe any key performance indicators or success criteria. + +#### 3. Target Audience + - Identify the intended users or customer segments. + - Describe user needs, pain points, and how the product will address them. + +#### 4. User Stories + - List user stories that illustrate interactions for each main feature. + - Make each story actionable, focusing on user goals. + +#### 5. Features + - Outline each feature required for the project. + - Write the requirement for the feature + +#### 6. Functional Requirements + - Specify the functional requirements for each feature and sub-feature. + - Use clear, concise statements outlining required functionality. + +#### 7. Non-Functional Requirements + - Describe performance, security, usability, and other quality-related requirements. + +#### 8. Additional Analysis + - Provide any further insights or considerations to ensure a holistic view of the project requirements. +--- + + Your reply must start with : "\`\`\`ProductDoc" and end with "\`\`\`". Be thorough, and make sure each section is fully developed and ready for implementation. +`; + }, +}; diff --git a/backend/src/build-system/node/project-init.ts b/backend/src/build-system/node/project-init.ts index 767b5575..39eed570 100644 --- a/backend/src/build-system/node/project-init.ts +++ b/backend/src/build-system/node/project-init.ts @@ -8,7 +8,9 @@ export class ProjectInitHandler implements BuildHandler { async run(context: BuilderContext): Promise { console.log('Setting up project...'); const result = { - projectName: 'example', + projectName: 'online shoping', + descreption: 'sell products', + Platform: 'Web', path: '/path/to/project', }; context.setData('projectConfig', result); diff --git a/backend/src/chat/chat.service.ts b/backend/src/chat/chat.service.ts index 45b39766..8f5bc492 100644 --- a/backend/src/chat/chat.service.ts +++ b/backend/src/chat/chat.service.ts @@ -13,7 +13,6 @@ import { import { CustomAsyncIterableIterator } from 'src/common/model-provider/types'; import { ModelProvider } from 'src/common/model-provider'; - @Injectable() export class ChatProxyService { private readonly logger = new Logger('ChatProxyService'); diff --git a/backend/src/common/model-provider/index.ts b/backend/src/common/model-provider/index.ts index 12f133a8..c080a00f 100644 --- a/backend/src/common/model-provider/index.ts +++ b/backend/src/common/model-provider/index.ts @@ -51,7 +51,7 @@ export class ModelProvider { chat( input: ChatInput | string, - model?: string, + model: string, chatId?: string, ): CustomAsyncIterableIterator { const chatInput = this.normalizeChatInput(input); @@ -199,6 +199,19 @@ export class ModelProvider { } } + async chunkSync(chatStream: AsyncIterableIterator): Promise { + let aggregatedContent = ''; + for await (const chunk of chatStream) { + if (chunk.status === StreamStatus.STREAMING) { + aggregatedContent += chunk.choices + .map((choice) => choice.delta?.content || '') + .join(''); + } + } + this.logger.log('Aggregated content from chat stream:', aggregatedContent); + return aggregatedContent; + } + private startChat(input: ChatInput, model: string, chatId?: string) { const payload = this.createRequestPayload(input, model, chatId);