kamaleswar Mohanta commited on
Commit
c767cb0
·
1 Parent(s): a14f0be

Enhance requirement and user story generation prompts for clarity; implement feedback processing and download link for artifacts in Streamlit UI.

Browse files
src/langgraphagenticai/nodes/__pycache__/sdlc_node.cpython-312.pyc CHANGED
Binary files a/src/langgraphagenticai/nodes/__pycache__/sdlc_node.cpython-312.pyc and b/src/langgraphagenticai/nodes/__pycache__/sdlc_node.cpython-312.pyc differ
 
src/langgraphagenticai/nodes/sdlc_node.py CHANGED
@@ -42,7 +42,14 @@ class SdlcNode:
42
  "project_scope": state.project_scope if state.project_scope is not None else "No project scope provided",
43
  "project_objectives": state.project_objectives if state.project_objectives is not None else "No project objectives provided",
44
  }
45
- prompt_string = f"Generate detailed requirements for the following project details:\n{json.dumps(requirements_input, indent=2)}"
 
 
 
 
 
 
 
46
  # Construct a list of messages for the LLM
47
  messages = [SystemMessage(content="You are an expert project requirements generator."),HumanMessage(content=prompt_string)]
48
  state.generated_requirements = self.llm(messages)
@@ -60,7 +67,15 @@ class SdlcNode:
60
 
61
  try:
62
  if state.generated_requirements:
63
- prompt_string = f"Generate user stories based on the following requirements:\n{state.generated_requirements}"
 
 
 
 
 
 
 
 
64
  messages = [
65
  SystemMessage(content="You are an expert at creating user stories for software development projects. Each user story should follow the format: 'As a [type of user], I want [some goal] so that [some reason/benefit].' Ensure the user stories are clear, concise, and cover the key functionalities outlined in the requirements."),
66
  HumanMessage(content=prompt_string)
@@ -73,4 +88,77 @@ class SdlcNode:
73
  except Exception as e:
74
  logger.error(f"Error generating user stories: {e}")
75
  state.user_stories = f"Error generating user stories: {str(e)}"
76
- return {"user_stories": state.user_stories}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
42
  "project_scope": state.project_scope if state.project_scope is not None else "No project scope provided",
43
  "project_objectives": state.project_objectives if state.project_objectives is not None else "No project objectives provided",
44
  }
45
+ prompt_string = f"""Based on the following project details, generate a comprehensive list of detailed software requirements.
46
+ Ensure the requirements are clear, unambiguous, verifiable, and complete based on the provided description, goals, scope, and objectives.
47
+
48
+ Project Details:
49
+ {json.dumps(requirements_input, indent=2)}
50
+
51
+ Detailed Requirements:
52
+ """""
53
  # Construct a list of messages for the LLM
54
  messages = [SystemMessage(content="You are an expert project requirements generator."),HumanMessage(content=prompt_string)]
55
  state.generated_requirements = self.llm(messages)
 
67
 
68
  try:
69
  if state.generated_requirements:
70
+ prompt_string = f"""Based on the following software requirements, generate a list of user stories.
71
+ Each user story should follow the format: 'As a [type of user], I want [some goal] so that [some reason/benefit].'
72
+ Ensure the user stories cover the key functionalities outlined in the requirements and are actionable from a development perspective.
73
+
74
+ Requirements:
75
+ {state.generated_requirements}
76
+
77
+ User Stories:
78
+ """""
79
  messages = [
80
  SystemMessage(content="You are an expert at creating user stories for software development projects. Each user story should follow the format: 'As a [type of user], I want [some goal] so that [some reason/benefit].' Ensure the user stories are clear, concise, and cover the key functionalities outlined in the requirements."),
81
  HumanMessage(content=prompt_string)
 
88
  except Exception as e:
89
  logger.error(f"Error generating user stories: {e}")
90
  state.user_stories = f"Error generating user stories: {str(e)}"
91
+ return {"user_stories": state.user_stories}
92
+
93
+ @log_entry_exit
94
+ def process_feedback(self, state: State) -> dict:
95
+ """Process user feedback received for the current stage's output."""
96
+ logger.info(f"Processing user feedback for stage: {state.current_stage.value}")
97
+
98
+ # Assume feedback is available in Streamlit's session state when this node is triggered
99
+ feedback_text = st.session_state.get("user_feedback")
100
+
101
+ if feedback_text and feedback_text.strip(): # Check if feedback exists and is not just whitespace
102
+ logger.info(f"Feedback received: {feedback_text}")
103
+ # Add feedback to the state associated with the current stage
104
+ # The feedback is typically about the *output* of the previous stage,
105
+ # but we associate it with the *current* stage where it's processed.
106
+ # Or, one could argue it belongs to the stage *just completed*.
107
+ # Let's associate it with the stage that produced the artifact being reviewed.
108
+ # If this node is called *after* generating user stories (part of PLANNING),
109
+ # then the feedback is about the planning artifacts.
110
+ stage_for_feedback = SDLCStages.PLANNING # Assuming feedback after user stories review is about planning
111
+ state.add_feedback(stage_for_feedback, feedback_text)
112
+ logger.info(f"Feedback added for stage: {stage_for_feedback.value}")
113
+
114
+ # Clear the feedback from session state after processing
115
+ if "user_feedback" in st.session_state:
116
+ del st.session_state["user_feedback"]
117
+ logger.info("Feedback cleared from session state.")
118
+
119
+ # You might want to store the raw feedback text temporarily or trigger a revision process
120
+ # state.raw_feedback = feedback_text # Example of storing raw feedback if needed
121
+
122
+ return {"feedback_processed": True, "status": "feedback_added"}
123
+ else:
124
+ logger.info("No new user feedback found in session state.")
125
+ return {"feedback_processed": False, "status": "no_feedback"}
126
+
127
+ # Add more nodes for Design, Development, Testing, Deployment etc. following a similar pattern
128
+ # Each node would take the state, perform an action (potentially using LLM),
129
+ # update the state with the generated artifact, and return a dict indicating the result.
130
+
131
+ # Example placeholder for a Planning Review node (determines next step after planning)
132
+ @log_entry_exit
133
+ def planning_review(self, state: State) -> str:
134
+ """Determines the next step after the planning stage."""
135
+ logger.info("Executing planning_review.")
136
+
137
+ # Check if feedback was provided in the previous step
138
+ feedback_given = st.session_state.get("feedback_submitted", False) # Assuming a flag is set in Streamlit
139
+
140
+ if feedback_given:
141
+ # Clear the feedback flag
142
+ if "feedback_submitted" in st.session_state:
143
+ del st.session_state["feedback_submitted"]
144
+ # If feedback was given, we might want to revise planning or user stories
145
+ # This decision logic would go here. For simplicity, let's assume
146
+ # feedback means we go back to regeneration or processing the feedback more deeply.
147
+ # A more complex graph might have a dedicated feedback processing node.
148
+ logger.info("Feedback detected, potentially returning for revision or processing.")
149
+ # Return node names or conditional edges based on feedback content or presence
150
+ # Example: return "process_feedback_node" or "generate_requirements"
151
+ return "process_feedback" # Assuming the process_feedback node handles the revision logic
152
+
153
+ # If no feedback, proceed to the next stage
154
+ next_stage_enum = state.get_next_stage() # Get the next enum stage (e.g., SDLCStages.DESIGN)
155
+
156
+ if next_stage_enum and next_stage_enum != SDLCStages.COMPLETE:
157
+ next_stage_name = next_stage_enum.value # Get the string name (e.g., "design")
158
+ logger.info(f"No feedback detected. Proceeding to the next stage: {next_stage_name}")
159
+ # In LangGraph, return the name of the node to transition to
160
+ # Assuming you have nodes named "design", "development", etc.
161
+ return next_stage_name
162
+ else:
163
+ logger.info("Planning complete, no further stages defined or project is complete.")
164
+ return "end" # Indicate completion of the workflow or section
src/langgraphagenticai/ui/streamlitui/__pycache__/display_result_sdlc.cpython-312.pyc CHANGED
Binary files a/src/langgraphagenticai/ui/streamlitui/__pycache__/display_result_sdlc.cpython-312.pyc and b/src/langgraphagenticai/ui/streamlitui/__pycache__/display_result_sdlc.cpython-312.pyc differ
 
src/langgraphagenticai/ui/streamlitui/display_result_sdlc.py CHANGED
@@ -95,14 +95,12 @@ class DisplaySdlcResult:
95
  with st.expander("Generated Requirements"):
96
  st.subheader("Generated Requirements")
97
  st.markdown(st.session_state["generated_requirements"].content)
98
- self._create_download_link(st.session_state["generated_requirements"].content, "requirements.txt", "Download Requirements")
99
  if st.button("Save Requirements", key="save_requirements_planning"): # Unique key
100
  self._save_artifact(st.session_state["generated_requirements"].content, "requirements.txt")
101
  if st.session_state.get("user_stories_generated"):
102
  with st.expander("Generated User Stories"):
103
  st.subheader("Generated User Stories")
104
  st.markdown(st.session_state["generated_user_stories"].content)
105
- self._create_download_link(st.session_state["generated_user_stories"].content, "user_stories.txt", "Download User Stories")
106
  if st.button("Save User Stories", key="save_user_stories_planning"): # Unique key
107
  self._save_artifact(st.session_state["generated_user_stories"].content, "user_stories.txt")
108
  if not st.session_state.get("requirements_generated") and not st.session_state.get("user_stories_generated"):
@@ -264,43 +262,14 @@ class DisplaySdlcResult:
264
  st.session_state["requirements_generated"] = requirements is not None
265
  st.session_state["user_stories_generated"] = user_stories is not None
266
 
267
- def _create_download_link(self, data, filename, label):
268
- """Creates a download link for the given data."""
269
- b64 = base64.b64encode(data.encode()).decode()
270
- href = f'<a href="data:file/txt;base64,{b64}" download="{filename}">{label}</a>'
271
- st.markdown(href, unsafe_allow_html=True)
272
 
273
  def _save_artifact(self, data, filename):
274
- """Saves the artifact data to a file in a user-specified directory."""
275
  try:
276
- # Get the current working directory as default
277
- default_dir = os.getcwd()
278
-
279
- # Ask user for directory path
280
- dir_path = st.text_input(
281
- "Enter directory path to save the file:",
282
- value=default_dir,
283
- help="Specify the directory where you want to save the file"
284
- )
285
-
286
- # Create a button to save the file
287
- if st.button("Save File"):
288
- # Check if directory exists
289
- if not os.path.exists(dir_path):
290
- st.warning(f"Directory does not exist: {dir_path}")
291
- create_dir = st.button("Create directory?")
292
- if create_dir:
293
- os.makedirs(dir_path)
294
- else:
295
- return
296
-
297
- # Create full filepath
298
- filepath = os.path.join(dir_path, filename)
299
-
300
- # Save the file
301
- with open(filepath, "w") as f:
302
- f.write(data)
303
-
304
- st.success(f"Artifact saved to {filepath}")
305
  except Exception as e:
306
- st.error(f"Error saving artifact: {e}")
 
95
  with st.expander("Generated Requirements"):
96
  st.subheader("Generated Requirements")
97
  st.markdown(st.session_state["generated_requirements"].content)
 
98
  if st.button("Save Requirements", key="save_requirements_planning"): # Unique key
99
  self._save_artifact(st.session_state["generated_requirements"].content, "requirements.txt")
100
  if st.session_state.get("user_stories_generated"):
101
  with st.expander("Generated User Stories"):
102
  st.subheader("Generated User Stories")
103
  st.markdown(st.session_state["generated_user_stories"].content)
 
104
  if st.button("Save User Stories", key="save_user_stories_planning"): # Unique key
105
  self._save_artifact(st.session_state["generated_user_stories"].content, "user_stories.txt")
106
  if not st.session_state.get("requirements_generated") and not st.session_state.get("user_stories_generated"):
 
262
  st.session_state["requirements_generated"] = requirements is not None
263
  st.session_state["user_stories_generated"] = user_stories is not None
264
 
 
 
 
 
 
265
 
266
  def _save_artifact(self, data, filename):
267
+ """Saves the artifact data to a file, prompting the user for the download."""
268
  try:
269
+ # Create a download link using streamlit
270
+ b64 = base64.b64encode(data.encode()).decode()
271
+ st.markdown(f'<a href="data:file/txt;base64,{b64}" download="{filename}">Download {filename}</a>', unsafe_allow_html=True)
272
+ st.success(f"Artifact download link created. Click to download {filename}")
273
+
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
274
  except Exception as e:
275
+ st.error(f"Error creating download link: {e}")