Backend (FastAPI + SQLAlchemy + Claude API + RAG): - Config management with Pydantic v2 - Database engine with connection pooling and SQL injection prevention - AI engine with Claude API integration (support custom base URL) - RAG engine with ChromaDB and sentence-transformers - Requirement analysis service - Config generation service - Executor engine with SQL validation - REST API endpoints: /analyze, /generate, /execute Frontend (Vue 3 + Element Plus + Pinia): - Complete 3-step workflow: analyze → generate → execute - Step indicator with progress visualization - Analysis result display with field table - SQL preview with monospace font - Execute confirmation dialog with safety warning - Execution result display - State management with Pinia - API service integration Security: - SQL injection prevention with parameterized queries - Dangerous SQL operation blocking - Database password URL encoding - Transaction auto-rollback - Pydantic config validation Features: - Natural language requirement analysis - Automated SQL configuration generation - Safe execution with human review - LAN access support - Custom Claude API endpoint support Documentation: - README with quick start guide - Quick start guide - LAN access configuration - Dependency fixes guide - Claude API configuration - Git operation guide - Implementation report Dependencies fixed: - numpy<2.0.0 for chromadb compatibility - sentence-transformers==2.7.0 for huggingface_hub compatibility Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
147 lines
5.2 KiB
Python
147 lines
5.2 KiB
Python
"""Requirement Analysis Service.
|
|
|
|
This module provides the RequirementService class for analyzing user requirements
|
|
using Claude AI with RAG knowledge retrieval.
|
|
"""
|
|
|
|
from typing import Optional, Dict, Any
|
|
import uuid
|
|
|
|
from loguru import logger
|
|
|
|
from app.core.ai_engine import ClaudeEngine
|
|
from app.core.rag_engine import RAGEngine
|
|
from app.core.prompts import SYSTEM_PROMPT, ANALYZE_PROMPT_TEMPLATE
|
|
from app.core.db_engine import DatabaseEngine
|
|
|
|
|
|
class RequirementService:
|
|
"""Service for analyzing user requirements with AI assistance.
|
|
|
|
This service integrates Claude AI, RAG knowledge retrieval, and database
|
|
metadata to provide comprehensive requirement analysis.
|
|
"""
|
|
|
|
def __init__(self) -> None:
|
|
"""Initialize requirement service with required engines."""
|
|
self.ai_engine = ClaudeEngine()
|
|
self.rag_engine = RAGEngine()
|
|
self.db_engine = DatabaseEngine()
|
|
logger.info("RequirementService initialized")
|
|
|
|
async def analyze(
|
|
self,
|
|
user_input: str,
|
|
session_id: Optional[str] = None
|
|
) -> Dict[str, Any]:
|
|
"""Analyze user requirement and generate structured specification.
|
|
|
|
Args:
|
|
user_input: Natural language requirement from user
|
|
session_id: Session ID for context management (auto-generated if None)
|
|
|
|
Returns:
|
|
Structured requirement document as dictionary
|
|
|
|
Raises:
|
|
ValueError: If user_input is empty
|
|
Exception: If AI analysis fails
|
|
"""
|
|
# Validate input
|
|
if not user_input or not user_input.strip():
|
|
raise ValueError("User input cannot be empty")
|
|
|
|
# Generate session ID if not provided
|
|
session_id = session_id or str(uuid.uuid4())
|
|
logger.info(f"[{session_id}] Starting requirement analysis: {user_input[:50]}...")
|
|
|
|
try:
|
|
# Step 1: Retrieve relevant knowledge from RAG
|
|
logger.debug(f"[{session_id}] Searching knowledge base")
|
|
knowledge_results = self.rag_engine.search(user_input, top_k=3)
|
|
knowledge_context = self._format_knowledge_context(knowledge_results)
|
|
logger.info(f"[{session_id}] Retrieved {len(knowledge_results)} knowledge chunks")
|
|
|
|
# Step 2: Query existing database tables
|
|
logger.debug(f"[{session_id}] Querying existing tables")
|
|
existing_tables = self._get_existing_tables(user_input)
|
|
logger.info(f"[{session_id}] Retrieved existing table information")
|
|
|
|
# Step 3: Build prompt
|
|
prompt = ANALYZE_PROMPT_TEMPLATE.format(
|
|
user_input=user_input,
|
|
knowledge_context=knowledge_context,
|
|
existing_tables=existing_tables
|
|
)
|
|
|
|
messages = [
|
|
{"role": "user", "content": SYSTEM_PROMPT},
|
|
{"role": "assistant", "content": "我已了解平台配置规范,请告诉我您的需求。"},
|
|
{"role": "user", "content": prompt}
|
|
]
|
|
|
|
# Step 4: Call Claude API
|
|
logger.debug(f"[{session_id}] Calling Claude API")
|
|
response = await self.ai_engine.call_claude(messages, temperature=0.7)
|
|
|
|
# Step 5: Parse JSON response
|
|
result = self.ai_engine.parse_json_response(response)
|
|
|
|
function_name = result.get("功能名称", "Unknown")
|
|
logger.success(f"[{session_id}] Requirement analysis completed: {function_name}")
|
|
|
|
return result
|
|
|
|
except Exception as e:
|
|
logger.error(f"[{session_id}] Requirement analysis failed: {e}")
|
|
raise
|
|
|
|
def _format_knowledge_context(self, knowledge_results: list) -> str:
|
|
"""Format knowledge search results into context string.
|
|
|
|
Args:
|
|
knowledge_results: List of knowledge search results
|
|
|
|
Returns:
|
|
Formatted knowledge context string
|
|
"""
|
|
if not knowledge_results:
|
|
return "未找到相关知识库内容"
|
|
|
|
context_parts = []
|
|
for result in knowledge_results:
|
|
source = result.get("metadata", {}).get("source", "文档")
|
|
content = result.get("content", "")
|
|
if content:
|
|
context_parts.append(f"【{source}】\n{content}")
|
|
|
|
return "\n\n".join(context_parts) if context_parts else "未找到相关知识库内容"
|
|
|
|
def _get_existing_tables(self, user_input: str) -> str:
|
|
"""Query existing database tables relevant to user input.
|
|
|
|
Args:
|
|
user_input: User requirement text
|
|
|
|
Returns:
|
|
Formatted string listing existing tables
|
|
"""
|
|
try:
|
|
# Query top 10 tables (simplified version - could be enhanced with relevance matching)
|
|
sql = """
|
|
SELECT TOP 10 TABLE_NAME
|
|
FROM INFORMATION_SCHEMA.TABLES
|
|
WHERE TABLE_TYPE = 'BASE TABLE'
|
|
ORDER BY TABLE_NAME
|
|
"""
|
|
tables = self.db_engine.execute_sql(sql)
|
|
|
|
if not tables:
|
|
return "未找到现有数据表"
|
|
|
|
table_list = [f"- {t[0]}" for t in tables]
|
|
return "\n".join(table_list)
|
|
|
|
except Exception as e:
|
|
logger.warning(f"Failed to query existing tables: {e}")
|
|
return "无法获取现有表信息" |