diff --git a/.gitignore b/.gitignore index 4cb9aa78..4c8bf81d 100644 --- a/.gitignore +++ b/.gitignore @@ -11,7 +11,7 @@ __pycache__/ .venv/ env/ venv/ -*.env* +*.env .env_example diff --git a/prompts/code_prompts.py b/prompts/code_prompts.py index 11d925b6..5bfd8c29 100644 --- a/prompts/code_prompts.py +++ b/prompts/code_prompts.py @@ -13,6 +13,10 @@ - PAPER_ALGORITHM_ANALYSIS_PROMPT: 专注算法提取,明确实现优先级 - PAPER_CONCEPT_ANALYSIS_PROMPT: 专注系统架构,突出概念到代码的映射 - CODE_PLANNING_PROMPT: 整合前两者输出,生成高质量复现计划 + +NEW: 用户需求分析相关提示词 +- REQUIREMENT_QUESTION_GENERATION_PROMPT: 基于初始需求生成引导性问题 +- REQUIREMENT_SUMMARY_PROMPT: 基于问答生成详细需求文档 """ # Paper to Code Workflow Prompts diff --git a/prompts/requirement_analysis_prompts.py b/prompts/requirement_analysis_prompts.py new file mode 100644 index 00000000..d8987826 --- /dev/null +++ b/prompts/requirement_analysis_prompts.py @@ -0,0 +1,71 @@ +""" +User requirement analysis related prompt templates + +Contains prompt templates for requirement analysis Agent, supporting question generation and requirement summarization functions. +""" + +# ======================================== +# User requirement analysis related prompt templates +# ======================================== + +REQUIREMENT_QUESTION_GENERATION_PROMPT = """You are a professional requirement analysis expert, skilled at helping users refine project requirements through precise questions. + +Please generate 1-3 precise guiding questions based on user's initial requirement description to help users provide more detailed information. + +User Initial Requirements: +{user_input} + +Please generate a JSON format question list, each question contains the following fields: +- category: Question category (such as "Functional Requirements", "Technology Selection", "Performance Requirements", "User Interface", "Deployment Environment", etc.) +- question: Specific question content +- importance: Importance level ("High", "Medium", "Low") +- hint: Question hint or example (optional) + +Requirements: +1. Questions should be highly targeted, based on user's specific requirement scenarios +2. Cover key decision points for project implementation +3. Avoid overly technical questions, maintain user-friendliness +4. Questions should have logical correlation +5. Ensure questions help users think about important details they might have missed + +Please return JSON format results directly, without including other text descriptions.""" + +REQUIREMENT_SUMMARY_PROMPT = """You are a professional technical requirement analyst, skilled at converting user requirement descriptions into detailed technical specification documents. + +Please generate a detailed project requirement document based on user's initial requirements and supplementary responses. + +User Initial Requirements: +{initial_input} + +User Supplementary Responses: +{answers_text} + +Please generate a concise requirement document focusing on the following core sections: + +## Project Overview +Brief description of project's core goals and value proposition + +## Functional Requirements +Detailed list of required features and functional modules: +- Core functionalities +- User interactions and workflows +- Data processing requirements +- Integration needs + +## Technical Architecture +Recommended technical design including: +- Technology stack and frameworks +- System architecture design +- Database and data storage solutions +- API design considerations +- Security requirements + +## Performance & Scalability +- Expected user scale and performance requirements +- Scalability considerations and constraints + +Requirements: +1. Focus on what needs to be built and how to build it technically +2. Be concise but comprehensive - avoid unnecessary implementation details +3. Provide clear functional specifications and technical architecture guidance +4. Consider project feasibility and technical complexity""" diff --git a/ui/handlers.py b/ui/handlers.py index c680c978..181e07f6 100644 --- a/ui/handlers.py +++ b/ui/handlers.py @@ -882,6 +882,199 @@ def background_progress_callback(progress: int, message: str): } +async def handle_requirement_analysis_workflow( + user_input: str, + analysis_mode: str, + user_answers: Dict[str, str] = None +) -> Dict[str, Any]: + """ + Handle requirement analysis workflow + + Args: + user_input: User initial requirements + analysis_mode: Analysis mode ("generate_questions" or "summarize_requirements") + user_answers: User answer dictionary + + Returns: + Processing result dictionary + """ + try: + # Import required modules + from workflows.agent_orchestration_engine import execute_requirement_analysis_workflow + + # Create progress callback function + def update_progress(progress: int, message: str): + # Display progress in Streamlit + st.session_state.current_progress = progress + st.session_state.current_message = message + + # Execute requirement analysis workflow + result = await execute_requirement_analysis_workflow( + user_input=user_input, + analysis_mode=analysis_mode, + user_answers=user_answers, + logger=None, # Can pass in logger + progress_callback=update_progress + ) + + return result + + except Exception as e: + return { + "status": "error", + "error": str(e), + "message": f"Requirement analysis workflow execution failed: {str(e)}" + } + + +async def handle_requirement_modification_workflow( + current_requirements: str, + modification_feedback: str +) -> Dict[str, Any]: + """ + Handle requirement modification workflow + + Args: + current_requirements: Current requirement document content + modification_feedback: User's modification requests and feedback + + Returns: + Processing result dictionary + """ + try: + # Import required modules + from workflows.agents.requirement_analysis_agent import RequirementAnalysisAgent + from utils.llm_utils import get_preferred_llm_class + + # Create progress callback function + def update_progress(progress: int, message: str): + # Display progress in Streamlit + st.session_state.current_progress = progress + st.session_state.current_message = message + + update_progress(10, "🔧 Initializing requirement modification agent...") + + # Initialize RequirementAnalysisAgent + agent = RequirementAnalysisAgent() + + # Initialize agent (LLM is initialized internally) + await agent.initialize() + + update_progress(50, "✏️ Modifying requirements based on your feedback...") + + # Modify requirements + result = await agent.modify_requirements( + current_requirements=current_requirements, + modification_feedback=modification_feedback + ) + + # Cleanup + await agent.cleanup() + + update_progress(100, "✅ Requirements modification completed!") + + return { + "status": "success", + "result": result, + "message": "Requirements modification completed successfully" + } + + except Exception as e: + return { + "status": "error", + "error": str(e), + "message": f"Requirements modification workflow execution failed: {str(e)}" + } + + +def handle_guided_mode_processing(): + """Handle asynchronous processing for guided mode""" + # Check if questions need to be generated + if st.session_state.get("questions_generating", False): + st.session_state.questions_generating = False + + # Asynchronously generate questions + initial_req = st.session_state.get("initial_requirement", "") + if initial_req: + try: + # Use asynchronous processing to generate questions + result = run_async_task_simple( + handle_requirement_analysis_workflow( + user_input=initial_req, + analysis_mode="generate_questions" + ) + ) + + if result["status"] == "success": + # Parse JSON result + import json + questions = json.loads(result["result"]) + st.session_state.generated_questions = questions + else: + st.error(f"Question generation failed: {result.get('error', 'Unknown error')}") + + except Exception as e: + st.error(f"Question generation exception: {str(e)}") + + # Check if detailed requirements need to be generated + if st.session_state.get("requirements_generating", False): + st.session_state.requirements_generating = False + + # Asynchronously generate detailed requirements + initial_req = st.session_state.get("initial_requirement", "") + user_answers = st.session_state.get("user_answers", {}) + + if initial_req: + try: + # Use asynchronous processing to generate requirement summary + result = run_async_task_simple( + handle_requirement_analysis_workflow( + user_input=initial_req, + analysis_mode="summarize_requirements", + user_answers=user_answers + ) + ) + + if result["status"] == "success": + st.session_state.detailed_requirements = result["result"] + else: + st.error(f"Requirement summary generation failed: {result.get('error', 'Unknown error')}") + + except Exception as e: + st.error(f"Requirement summary generation exception: {str(e)}") + + # Check if requirements need to be edited + if st.session_state.get("requirements_editing", False): + st.session_state.requirements_editing = False + st.info("🔧 Starting requirement modification process...") + + # Asynchronously modify requirements based on user feedback + current_requirements = st.session_state.get("detailed_requirements", "") + edit_feedback = st.session_state.get("edit_feedback", "") + + if current_requirements and edit_feedback: + try: + # Use asynchronous processing to modify requirements + result = run_async_task_simple( + handle_requirement_modification_workflow( + current_requirements=current_requirements, + modification_feedback=edit_feedback + ) + ) + + if result["status"] == "success": + st.session_state.detailed_requirements = result["result"] + st.session_state.requirement_analysis_step = "summary" + st.session_state.edit_feedback = "" + st.success("✅ Requirements updated successfully!") + st.rerun() + else: + st.error(f"Requirements modification failed: {result.get('error', 'Unknown error')}") + + except Exception as e: + st.error(f"Requirements modification exception: {str(e)}") + + def handle_start_processing_button(input_source: str, input_type: str): """ Handle start processing button click - synchronous execution @@ -1034,6 +1227,30 @@ def initialize_session_state(): st.session_state.enable_indexing = ( False # Default enable indexing functionality ) + + # Requirement analysis related states + if "requirement_analysis_mode" not in st.session_state: + st.session_state.requirement_analysis_mode = "direct" # direct/guided + if "requirement_analysis_step" not in st.session_state: + st.session_state.requirement_analysis_step = "input" # input/questions/summary + if "generated_questions" not in st.session_state: + st.session_state.generated_questions = [] + if "user_answers" not in st.session_state: + st.session_state.user_answers = {} + if "detailed_requirements" not in st.session_state: + st.session_state.detailed_requirements = "" + if "initial_requirement" not in st.session_state: + st.session_state.initial_requirement = "" + if "questions_generating" not in st.session_state: + st.session_state.questions_generating = False + if "requirements_generating" not in st.session_state: + st.session_state.requirements_generating = False + if "requirements_confirmed" not in st.session_state: + st.session_state.requirements_confirmed = False + if "edit_feedback" not in st.session_state: + st.session_state.edit_feedback = "" + if "requirements_editing" not in st.session_state: + st.session_state.requirements_editing = False # Requirement analysis related states if "requirement_analysis_mode" not in st.session_state: diff --git a/workflows/agent_orchestration_engine.py b/workflows/agent_orchestration_engine.py index 056f44b8..99c7c1d0 100644 --- a/workflows/agent_orchestration_engine.py +++ b/workflows/agent_orchestration_engine.py @@ -1533,6 +1533,61 @@ async def synthesize_code_implementation_agent( return {"status": "error", "message": str(e)} +async def run_requirement_analysis_agent( + user_input: str, + analysis_mode: str, + user_answers: Dict[str, str] = None, + logger=None +) -> str: + """ + Run requirement analysis Agent for question generation or requirement summarization + + Args: + user_input: User's initial requirement description + analysis_mode: Analysis mode ("generate_questions" or "summarize_requirements") + user_answers: User's answer dictionary for questions (only used in summarize_requirements mode) + logger: Logger instance + + Returns: + str: Generated question JSON string or detailed requirement document + """ + try: + print(f"🧠 Starting requirement analysis Agent, mode: {analysis_mode}") + print(f"Input length: {len(user_input) if user_input else 0}") + + if not user_input or user_input.strip() == "": + raise ValueError("User input cannot be empty") + + # Import requirement analysis Agent + from workflows.agents.requirement_analysis_agent import RequirementAnalysisAgent + + # Create requirement analysis Agent instance + async with RequirementAnalysisAgent(logger=logger) as req_agent: + if analysis_mode == "generate_questions": + # Generate guiding questions + print("📝 Generating guiding questions...") + questions = await req_agent.generate_guiding_questions(user_input) + return json.dumps(questions, ensure_ascii=False, indent=2) + + elif analysis_mode == "summarize_requirements": + # Summarize detailed requirements + print("📋 Summarizing detailed requirements...") + if user_answers is None: + user_answers = {} + summary = await req_agent.summarize_detailed_requirements( + user_input, user_answers + ) + return summary + + else: + raise ValueError(f"Unsupported analysis mode: {analysis_mode}") + + except Exception as e: + print(f"❌ Requirement analysis Agent execution failed: {e}") + print(f"Exception details: {type(e).__name__}: {str(e)}") + raise + + async def run_chat_planning_agent(user_input: str, logger) -> str: """ Run the chat-based planning agent for user-provided coding requirements. @@ -2026,3 +2081,188 @@ async def execute_chat_based_planning_pipeline( except Exception as e: print(f"Error in execute_chat_based_planning_pipeline: {e}") raise e + + +async def execute_requirement_analysis_workflow( + user_input: str, + analysis_mode: str, + user_answers: Dict[str, str] = None, + logger=None, + progress_callback: Optional[Callable] = None +) -> Dict[str, Any]: + """ + Execute user requirement analysis workflow + + This function supports two modes: + 1. generate_questions: Generate guiding questions based on user initial requirements + 2. summarize_requirements: Generate detailed requirement document based on user answers + + Args: + user_input: User's initial requirement description + analysis_mode: Analysis mode ("generate_questions" or "summarize_requirements") + user_answers: User's answer dictionary for questions + logger: Logger instance + progress_callback: Progress callback function + + Returns: + Dict[str, Any]: Dictionary containing analysis results + """ + try: + print(f"🧠 Starting requirement analysis workflow, mode: {analysis_mode}") + + if progress_callback: + if analysis_mode == "generate_questions": + progress_callback(10, "🤔 Analyzing user requirements, generating guiding questions...") + else: + progress_callback(10, "📝 Integrating user answers, generating detailed requirement document...") + + # Call requirement analysis Agent + result = await run_requirement_analysis_agent( + user_input=user_input, + analysis_mode=analysis_mode, + user_answers=user_answers, + logger=logger + ) + + if progress_callback: + progress_callback(100, "✅ Requirement analysis completed!") + + return { + "status": "success", + "mode": analysis_mode, + "result": result, + "message": f"Requirement analysis ({analysis_mode}) executed successfully" + } + + except Exception as e: + error_msg = f"Requirement analysis workflow execution failed: {str(e)}" + print(f"❌ {error_msg}") + + if progress_callback: + progress_callback(0, f"❌ {error_msg}") + + return { + "status": "error", + "mode": analysis_mode, + "error": error_msg, + "message": "Requirement analysis workflow execution failed" + } + + +async def run_requirement_analysis_agent( + user_input: str, + analysis_mode: str, + user_answers: Dict[str, str] = None, + logger=None +) -> str: + """ + Run requirement analysis agent + + Args: + user_input: User input text + analysis_mode: Analysis mode ("generate_questions" or "summarize_requirements") + user_answers: User answer dictionary + logger: Logger instance + + Returns: + str: Analysis result (JSON string for questions, markdown for summary) + """ + try: + # Import required modules + import json + from workflows.agents.requirement_analysis_agent import RequirementAnalysisAgent + from utils.llm_utils import get_preferred_llm_class + + if logger: + logger.info(f"Starting requirement analysis agent, mode: {analysis_mode}") + + # Initialize RequirementAnalysisAgent + agent = RequirementAnalysisAgent() + + # Initialize agent (LLM is initialized internally) + await agent.initialize() + + # Execute based on analysis mode + if analysis_mode == "generate_questions": + # Generate guiding questions + questions = await agent.generate_guiding_questions(user_input) + result = json.dumps(questions, ensure_ascii=False, indent=2) + elif analysis_mode == "summarize_requirements": + # Generate detailed requirements + result = await agent.summarize_detailed_requirements(user_input, user_answers or {}) + else: + raise ValueError(f"Unknown analysis mode: {analysis_mode}") + + # Cleanup + await agent.cleanup() + + if logger: + logger.info(f"Requirement analysis agent completed, result length: {len(result)}") + + return result + + except Exception as e: + error_msg = f"Requirement analysis agent execution failed: {str(e)}" + if logger: + logger.error(error_msg) + raise Exception(error_msg) + + +async def execute_requirement_analysis_workflow( + user_input: str, + analysis_mode: str, + user_answers: Dict[str, str] = None, + logger=None, + progress_callback=None +) -> Dict[str, Any]: + """ + Execute requirement analysis workflow + + Args: + user_input: User input text + analysis_mode: Analysis mode ("generate_questions" or "summarize_requirements") + user_answers: User answer dictionary + logger: Logger instance + progress_callback: Progress callback function + + Returns: + dict: Workflow execution result + """ + try: + if progress_callback: + if analysis_mode == "generate_questions": + progress_callback(10, "🤔 Analyzing user requirements, generating guiding questions...") + else: + progress_callback(10, "📝 Integrating user answers, generating detailed requirement document...") + + # Call requirement analysis Agent + result = await run_requirement_analysis_agent( + user_input=user_input, + analysis_mode=analysis_mode, + user_answers=user_answers, + logger=logger + ) + + if progress_callback: + progress_callback(100, "✅ Requirement analysis completed!") + + return { + "status": "success", + "mode": analysis_mode, + "result": result, + "message": f"Requirement analysis ({analysis_mode}) executed successfully" + } + + except Exception as e: + error_msg = f"Requirement analysis workflow execution failed: {str(e)}" + print(f"❌ {error_msg}") + + if progress_callback: + progress_callback(0, f"❌ {error_msg}") + + return { + "status": "error", + "mode": analysis_mode, + "error": error_msg, + "message": "Requirement analysis workflow execution failed" + } \ No newline at end of file