feat: implement ERP AI Assistant Phase 1

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>
This commit is contained in:
2026-03-21 14:23:20 +00:00
commit acd73431ae
60 changed files with 11284 additions and 0 deletions

View File

@@ -0,0 +1,141 @@
"""Tests for Config Executor.
This module tests the ConfigExecutor class for SQL validation and execution.
"""
import pytest
from unittest.mock import MagicMock, patch
from app.core.executor import ConfigExecutor
def test_executor_init():
"""Test executor initialization."""
executor = ConfigExecutor()
assert executor.db_engine is not None
def test_validate_sql_safe():
"""Test validation of safe SQL statements."""
executor = ConfigExecutor()
# Test SELECT
is_valid, msg = executor.validate_sql("SELECT * FROM SYS_FORM")
assert is_valid is True
assert "验证通过" in msg
# Test INSERT
is_valid, msg = executor.validate_sql(
"INSERT INTO SYS_FORM (IKEY, FORM_NAME) VALUES (1, 'Test')"
)
assert is_valid is True
# Test UPDATE with safe WHERE clause
is_valid, msg = executor.validate_sql(
"UPDATE SYS_FORM SET FORM_NAME = 'Test' WHERE IKEY = 1"
)
assert is_valid is True
def test_validate_sql_dangerous():
"""Test validation catches dangerous SQL statements."""
executor = ConfigExecutor()
# Test DROP DATABASE
is_valid, msg = executor.validate_sql("DROP DATABASE test_db")
assert is_valid is False
assert "危险操作" in msg
# Test DROP TABLE
is_valid, msg = executor.validate_sql("DROP TABLE users")
assert is_valid is False
assert "危险操作" in msg
# Test TRUNCATE
is_valid, msg = executor.validate_sql("TRUNCATE TABLE important_data")
assert is_valid is False
assert "危险操作" in msg
# Test DELETE without WHERE
is_valid, msg = executor.validate_sql("DELETE FROM users")
assert is_valid is False
assert "危险操作" in msg
def test_execute_config_success():
"""Test successful execution of SQL list."""
with patch('app.core.executor.DatabaseEngine') as MockDBEngine:
mock_db_engine = MagicMock()
mock_db_engine.execute_transaction = MagicMock(return_value=True)
MockDBEngine.return_value = mock_db_engine
executor = ConfigExecutor()
sql_list = [
"INSERT INTO SYS_FORM (IKEY, FORM_NAME) VALUES (1, 'Test1')",
"INSERT INTO SYS_FORM (IKEY, FORM_NAME) VALUES (2, 'Test2')"
]
result = executor.execute_config(sql_list, session_id="test-session")
assert result["success"] is True
assert len(result["executed"]) == 2
assert result["failed"] is None
assert "成功执行" in result["message"]
def test_execute_config_validation_failure():
"""Test execution fails when SQL validation fails."""
executor = ConfigExecutor()
sql_list = [
"SELECT * FROM SYS_FORM",
"DROP DATABASE test" # Dangerous SQL
]
result = executor.execute_config(sql_list, session_id="test-session")
assert result["success"] is False
assert result["failed"] is not None
assert "验证失败" in result["message"]
assert len(result["executed"]) == 0
def test_execute_config_execution_failure():
"""Test execution handles database errors."""
with patch('app.core.executor.DatabaseEngine') as MockDBEngine:
mock_db_engine = MagicMock()
mock_db_engine.execute_transaction = MagicMock(
side_effect=Exception("Database connection error")
)
MockDBEngine.return_value = mock_db_engine
executor = ConfigExecutor()
sql_list = ["SELECT * FROM SYS_FORM"]
result = executor.execute_config(sql_list, session_id="test-session")
assert result["success"] is False
assert result["failed"] is not None
assert "执行失败" in result["message"]
def test_rollback_placeholder():
"""Test rollback functionality placeholder."""
executor = ConfigExecutor()
result = executor.rollback(session_id="test-session")
assert result["success"] is False
assert "待实现" in result["message"]
def test_dangerous_keywords_exist():
"""Test that dangerous keywords list is properly defined."""
executor = ConfigExecutor()
assert hasattr(executor, 'DANGEROUS_KEYWORDS')
assert len(executor.DANGEROUS_KEYWORDS) > 0
assert "DROP DATABASE" in executor.DANGEROUS_KEYWORDS
assert "DROP TABLE" in executor.DANGEROUS_KEYWORDS
assert "TRUNCATE TABLE" in executor.DANGEROUS_KEYWORDS