diff --git a/=0.1.9 b/=0.1.9 deleted file mode 100644 index 262ee14..0000000 --- a/=0.1.9 +++ /dev/null @@ -1,14 +0,0 @@ -Looking in indexes: https://mirrors.aliyun.com/pypi/simple -Collecting slowapi - Using cached https://mirrors.aliyun.com/pypi/packages/2b/bb/f71c4b7d7e7eb3fc1e8c0458a8979b912f40b58002b9fbf37729b8cb464b/slowapi-0.1.9-py3-none-any.whl (14 kB) -Collecting limits>=2.3 (from slowapi) - Using cached https://mirrors.aliyun.com/pypi/packages/40/96/4fcd44aed47b8fcc457653b12915fcad192cd646510ef3f29fd216f4b0ab/limits-5.6.0-py3-none-any.whl (60 kB) -Collecting deprecated>=1.2 (from limits>=2.3->slowapi) - Using cached https://mirrors.aliyun.com/pypi/packages/84/d0/205d54408c08b13550c733c4b85429e7ead111c7f0014309637425520a9a/deprecated-1.3.1-py2.py3-none-any.whl (11 kB) -Requirement already satisfied: packaging>=21 in /data/tw/miniconda3/envs/searchengine/lib/python3.10/site-packages (from limits>=2.3->slowapi) (25.0) -Requirement already satisfied: typing-extensions in /data/tw/miniconda3/envs/searchengine/lib/python3.10/site-packages (from limits>=2.3->slowapi) (4.15.0) -Collecting wrapt<3,>=1.10 (from deprecated>=1.2->limits>=2.3->slowapi) - Downloading https://mirrors.aliyun.com/pypi/packages/c6/93/5cf92edd99617095592af919cb81d4bff61c5dbbb70d3c92099425a8ec34/wrapt-2.0.1-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl (113 kB) -Installing collected packages: wrapt, deprecated, limits, slowapi - -Successfully installed deprecated-1.3.1 limits-5.6.0 slowapi-0.1.9 wrapt-2.0.1 diff --git a/restart.sh b/restart.sh new file mode 100755 index 0000000..cfdc746 --- /dev/null +++ b/restart.sh @@ -0,0 +1,50 @@ +#!/bin/bash + +# Restart script for SearchEngine services +# This script stops all services first, then starts them again + +cd "$(dirname "$0")" + +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +RED='\033[0;31m' +NC='\033[0m' + +echo -e "${GREEN}========================================${NC}" +echo -e "${GREEN}SearchEngine服务重启脚本${NC}" +echo -e "${GREEN}========================================${NC}" + +# Step 1: Stop all services +echo -e "\n${YELLOW}Step 1/2: 停止现有服务${NC}" +if [ -f "./scripts/stop.sh" ]; then + ./scripts/stop.sh + if [ $? -eq 0 ]; then + echo -e "${GREEN}✓ 所有服务已成功停止${NC}" + else + echo -e "${YELLOW}⚠ 停止服务时出现警告,继续重启流程${NC}" + fi +else + echo -e "${RED}✗ 停止脚本不存在,无法安全重启${NC}" + exit 1 +fi + +# Wait a moment for services to fully stop +echo -e "\n${YELLOW}等待服务完全关闭...${NC}" +sleep 3 + +# Step 2: Start all services +echo -e "\n${YELLOW}Step 2/2: 重新启动服务${NC}" +if [ -f "./run.sh" ]; then + ./run.sh + if [ $? -eq 0 ]; then + echo -e "${GREEN}========================================${NC}" + echo -e "${GREEN}服务重启完成!${NC}" + echo -e "${GREEN}========================================${NC}" + else + echo -e "${RED}✗ 服务启动失败${NC}" + exit 1 + fi +else + echo -e "${RED}✗ 启动脚本不存在,无法完成重启${NC}" + exit 1 +fi \ No newline at end of file diff --git a/run.sh b/run.sh new file mode 100755 index 0000000..e02f64c --- /dev/null +++ b/run.sh @@ -0,0 +1,111 @@ +#!/bin/bash + +# Production startup script for SearchEngine services +# This script starts frontend and backend services (no data ingestion) + +cd "$(dirname "$0")" + +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +RED='\033[0;31m' +NC='\033[0m' + +echo -e "${GREEN}========================================${NC}" +echo -e "${GREEN}SearchEngine服务启动脚本${NC}" +echo -e "${GREEN}========================================${NC}" + +# Create logs directory if it doesn't exist +mkdir -p logs + +# Step 1: Start backend in background +echo -e "\n${YELLOW}Step 1/2: 启动后端服务${NC}" +echo -e "${YELLOW}后端服务将在后台运行...${NC}" + +nohup ./scripts/start_backend.sh > logs/backend.log 2>&1 & +BACKEND_PID=$! +echo $BACKEND_PID > logs/backend.pid +echo -e "${GREEN}后端服务已启动 (PID: $BACKEND_PID)${NC}" +echo -e "${GREEN}日志文件: logs/backend.log${NC}" + +# Wait for backend to start +echo -e "${YELLOW}等待后端服务启动...${NC}" +MAX_RETRIES=30 +RETRY_COUNT=0 +BACKEND_READY=false + +while [ $RETRY_COUNT -lt $MAX_RETRIES ]; do + sleep 2 + if curl -s http://localhost:6002/ > /dev/null 2>&1; then + BACKEND_READY=true + break + fi + RETRY_COUNT=$((RETRY_COUNT + 1)) + echo -e "${YELLOW} 等待中... ($RETRY_COUNT/$MAX_RETRIES)${NC}" +done + +# Check if backend is running +if [ "$BACKEND_READY" = true ]; then + echo -e "${GREEN}✓ 后端服务运行正常${NC}" + # Try health check + if curl -s http://localhost:6002/admin/health > /dev/null 2>&1; then + echo -e "${GREEN}✓ 健康检查通过${NC}" + else + echo -e "${YELLOW}⚠ 健康检查未通过,但服务已启动${NC}" + fi +else + echo -e "${RED}✗ 后端服务启动失败,请检查日志: logs/backend.log${NC}" + echo -e "${YELLOW}提示: 后端服务可能需要更多时间启动,或者检查端口是否被占用${NC}" + exit 1 +fi + +# Step 2: Start frontend in background +echo -e "\n${YELLOW}Step 2/2: 启动前端服务${NC}" +echo -e "${YELLOW}前端服务将在后台运行...${NC}" + +nohup ./scripts/start_frontend.sh > logs/frontend.log 2>&1 & +FRONTEND_PID=$! +echo $FRONTEND_PID > logs/frontend.pid +echo -e "${GREEN}前端服务已启动 (PID: $FRONTEND_PID)${NC}" +echo -e "${GREEN}日志文件: logs/frontend.log${NC}" + +# Wait for frontend to start +echo -e "${YELLOW}等待前端服务启动...${NC}" +MAX_RETRIES=15 +RETRY_COUNT=0 +FRONTEND_READY=false + +while [ $RETRY_COUNT -lt $MAX_RETRIES ]; do + sleep 2 + if curl -s http://localhost:6003/ > /dev/null 2>&1; then + FRONTEND_READY=true + break + fi + RETRY_COUNT=$((RETRY_COUNT + 1)) + echo -e "${YELLOW} 等待中... ($RETRY_COUNT/$MAX_RETRIES)${NC}" +done + +# Check if frontend is running +if [ "$FRONTEND_READY" = true ]; then + echo -e "${GREEN}✓ 前端服务运行正常${NC}" +else + echo -e "${YELLOW}⚠ 前端服务可能还在启动中,请稍后访问${NC}" +fi + +echo -e "${GREEN}========================================${NC}" +echo -e "${GREEN}所有服务启动完成!${NC}" +echo -e "${GREEN}========================================${NC}" +echo "" +echo -e "访问地址:" +echo -e " ${GREEN}前端界面: http://localhost:6003${NC}" +echo -e " ${GREEN}后端API: http://localhost:6002${NC}" +echo -e " ${GREEN}API文档: http://localhost:6002/docs${NC}" +echo "" +echo -e "日志文件:" +echo -e " 后端: logs/backend.log" +echo -e " 前端: logs/frontend.log" +echo "" +echo -e "停止服务:" +echo -e " 所有服务: ./stop.sh" +echo -e " 单独停止后端: kill \$(cat logs/backend.pid)" +echo -e " 单独停止前端: kill \$(cat logs/frontend.pid)" +echo "" \ No newline at end of file diff --git a/scripts/stop.sh b/scripts/stop.sh index 336ced8..4a82380 100755 --- a/scripts/stop.sh +++ b/scripts/stop.sh @@ -63,6 +63,17 @@ if [ -f "logs/backend.pid" ]; then rm -f logs/backend.pid fi +if [ -f "logs/frontend.pid" ]; then + FRONTEND_PID=$(cat logs/frontend.pid 2>/dev/null) + if [ ! -z "$FRONTEND_PID" ] && kill -0 $FRONTEND_PID 2>/dev/null; then + echo "Stopping frontend server via PID file (PID: $FRONTEND_PID)..." + kill -TERM $FRONTEND_PID 2>/dev/null || true + sleep 2 + kill -KILL $FRONTEND_PID 2>/dev/null || true + fi + rm -f logs/frontend.pid +fi + echo "========================================" echo "All services stopped successfully!" echo "========================================" \ No newline at end of file diff --git a/start_all.sh b/start_all.sh deleted file mode 100755 index 7ca6ca1..0000000 --- a/start_all.sh +++ /dev/null @@ -1,132 +0,0 @@ -#!/bin/bash - -# One-click startup script for SearchEngine -# This script starts everything you need - -# Don't exit on error - we want to continue even if some checks fail -# set -e - -cd "$(dirname "$0")" - -GREEN='\033[0;32m' -YELLOW='\033[1;33m' -RED='\033[0;31m' -NC='\033[0m' - -echo -e "${GREEN}========================================${NC}" -echo -e "${GREEN}SearchEngine一键启动脚本${NC}" -echo -e "${GREEN}========================================${NC}" - -# Step 0: Stop existing services first -echo -e "\n${YELLOW}Step 0/5: 停止现有服务${NC}" -if [ -f "./scripts/stop.sh" ]; then - ./scripts/stop.sh - sleep 2 # Wait for services to fully stop -else - echo -e "${YELLOW}停止脚本不存在,手动检查端口...${NC}" - # Kill any existing processes on our ports - fuser -k 6002/tcp 2>/dev/null || true - fuser -k 6003/tcp 2>/dev/null || true - sleep 2 -fi - -# Step 1: Setup environment -echo -e "\n${YELLOW}Step 1/5: 设置环境${NC}" -./setup.sh - -# Step 2: Check if data is already ingested -echo -e "\n${YELLOW}Step 2/5: 检查数据${NC}" -source /home/tw/miniconda3/etc/profile.d/conda.sh -conda activate searchengine - -# Check if index exists -INDEX_EXISTS=$(python -c " -from config.env_config import get_es_config -from utils.es_client import ESClient -from config import ConfigLoader - -es_config = get_es_config() -es_client = ESClient(hosts=[es_config['host']], username=es_config.get('username'), password=es_config.get('password')) - -config_loader = ConfigLoader('config/schema') -config = config_loader.load_customer_config('customer1') - -if es_client.index_exists(config.es_index_name): - doc_count = es_client.count(config.es_index_name) - print(f'{doc_count}') -else: - print('0') -" 2>/dev/null || echo "0") - -if [ "$INDEX_EXISTS" = "0" ]; then - echo -e "${YELLOW}索引不存在,开始导入数据...${NC}" - echo -e "${YELLOW}注意: 首次导入会下载模型文件,可能需要10-30分钟${NC}" - echo -e "${YELLOW}导入1000条数据进行快速测试(跳过embedding以加快速度)${NC}" - ./scripts/ingest.sh 1000 true -else - echo -e "${GREEN}数据已存在,包含 $INDEX_EXISTS 条文档${NC}" -fi - -# Step 3: Start backend in background -echo -e "\n${YELLOW}Step 3/5: 启动后端服务${NC}" -echo -e "${YELLOW}后端服务将在后台运行...${NC}" -nohup ./scripts/start_backend.sh > logs/backend.log 2>&1 & -BACKEND_PID=$! -echo $BACKEND_PID > logs/backend.pid -echo -e "${GREEN}后端服务已启动 (PID: $BACKEND_PID)${NC}" -echo -e "${GREEN}日志文件: logs/backend.log${NC}" - -# Wait for backend to start -echo -e "${YELLOW}等待后端服务启动...${NC}" -MAX_RETRIES=12 -RETRY_COUNT=0 -BACKEND_READY=false - -while [ $RETRY_COUNT -lt $MAX_RETRIES ]; do - sleep 2 - if curl -s http://localhost:6002/ > /dev/null 2>&1; then - BACKEND_READY=true - break - fi - RETRY_COUNT=$((RETRY_COUNT + 1)) - echo -e "${YELLOW} 等待中... ($RETRY_COUNT/$MAX_RETRIES)${NC}" -done - -# Check if backend is running -if [ "$BACKEND_READY" = true ]; then - echo -e "${GREEN}✓ 后端服务运行正常${NC}" - # Try health check, but don't fail if it's not ready yet - if curl -s http://localhost:6002/admin/health > /dev/null 2>&1; then - echo -e "${GREEN}✓ 健康检查通过${NC}" - else - echo -e "${YELLOW}⚠ 健康检查未通过,但服务已启动${NC}" - fi -else - echo -e "${RED}✗ 后端服务启动失败,请检查日志: logs/backend.log${NC}" - echo -e "${YELLOW}提示: 后端服务可能需要更多时间启动,或者检查端口是否被占用${NC}" - # Don't exit - let user decide whether to continue -fi - -# Step 4: Start frontend -echo -e "\n${YELLOW}Step 4/5: 启动前端服务${NC}" -echo -e "${GREEN}========================================${NC}" -echo -e "${GREEN}所有服务启动完成!${NC}" -echo -e "${GREEN}========================================${NC}" -echo "" -echo -e "访问地址:" -echo -e " ${GREEN}前端界面: http://localhost:6003${NC}" -echo -e " ${GREEN}后端API: http://localhost:6002${NC}" -echo -e " ${GREEN}API文档: http://localhost:6002/docs${NC}" -echo "" -echo -e "日志文件:" -echo -e " 后端: logs/backend.log" -echo "" -echo -e "停止服务:" -echo -e " 后端: kill \$(cat logs/backend.pid)" -echo -e " 前端: Ctrl+C" -echo "" -echo -e "${YELLOW}正在启动前端服务...${NC}" -echo -e "${YELLOW}按 Ctrl+C 停止前端服务${NC}" -echo "" - -./scripts/start_frontend.sh diff --git a/test_all.sh b/test_all.sh new file mode 100755 index 0000000..3c62b66 --- /dev/null +++ b/test_all.sh @@ -0,0 +1,155 @@ +#!/bin/bash + +# Complete test script for SearchEngine +# This script performs full testing including data ingestion and service restart + +cd "$(dirname "$0")" + +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +RED='\033[0;31m' +NC='\033[0m' + +echo -e "${GREEN}========================================${NC}" +echo -e "${GREEN}SearchEngine完整测试脚本${NC}" +echo -e "${GREEN}========================================${NC}" + +# Step 1: Setup environment +echo -e "\n${YELLOW}Step 1/4: 设置环境${NC}" +if [ -f "./setup.sh" ]; then + ./setup.sh + if [ $? -eq 0 ]; then + echo -e "${GREEN}✓ 环境设置完成${NC}" + else + echo -e "${RED}✗ 环境设置失败${NC}" + exit 1 + fi +else + echo -e "${YELLOW}⚠ setup脚本不存在,跳过环境设置${NC}" +fi + +# Step 2: Check and ingest data if needed +echo -e "\n${YELLOW}Step 2/4: 检查并准备数据${NC}" +source /home/tw/miniconda3/etc/profile.d/conda.sh +conda activate searchengine + +# Check if index exists +INDEX_EXISTS=$(python -c " +from config.env_config import get_es_config +from utils.es_client import ESClient +from config import ConfigLoader + +try: + es_config = get_es_config() + es_client = ESClient(hosts=[es_config['host']], username=es_config.get('username'), password=es_config.get('password')) + + config_loader = ConfigLoader('config/schema') + config = config_loader.load_customer_config('customer1') + + if es_client.index_exists(config.es_index_name): + doc_count = es_client.count(config.es_index_name) + print(f'{doc_count}') + else: + print('0') +except Exception as e: + print(f'0') +" 2>/dev/null || echo "0") + +if [ "$INDEX_EXISTS" = "0" ]; then + echo -e "${YELLOW}索引不存在,开始导入数据...${NC}" + echo -e "${YELLOW}注意: 首次导入会下载模型文件,可能需要10-30分钟${NC}" + echo -e "${YELLOW}导入1000条数据进行快速测试(跳过embedding以加快速度)${NC}" + + if [ -f "./scripts/ingest.sh" ]; then + ./scripts/ingest.sh 1000 true + if [ $? -eq 0 ]; then + echo -e "${GREEN}✓ 数据导入完成${NC}" + else + echo -e "${RED}✗ 数据导入失败${NC}" + exit 1 + fi + else + echo -e "${RED}✗ 数据导入脚本不存在${NC}" + exit 1 + fi +else + echo -e "${GREEN}✓ 数据已存在,包含 $INDEX_EXISTS 条文档${NC}" +fi + +# Step 3: Restart services (stop first, then start) +echo -e "\n${YELLOW}Step 3/4: 重启服务${NC}" +if [ -f "./restart.sh" ]; then + ./restart.sh + if [ $? -eq 0 ]; then + echo -e "${GREEN}✓ 服务重启完成${NC}" + else + echo -e "${RED}✗ 服务重启失败${NC}" + exit 1 + fi +else + echo -e "${RED}✗ 重启脚本不存在${NC}" + exit 1 +fi + +# Step 4: Test the services +echo -e "\n${YELLOW}Step 4/4: 测试服务${NC}" +sleep 3 + +# Test backend health +echo -e "${YELLOW}测试后端服务健康状态...${NC}" +if curl -s http://localhost:6002/admin/health > /dev/null 2>&1; then + echo -e "${GREEN}✓ 后端服务健康检查通过${NC}" +else + echo -e "${YELLOW}⚠ 后端服务健康检查失败,但服务可能仍在启动${NC}" +fi + +# Test frontend +echo -e "${YELLOW}测试前端服务...${NC}" +if curl -s http://localhost:6003/ > /dev/null 2>&1; then + echo -e "${GREEN}✓ 前端服务可访问${NC}" +else + echo -e "${YELLOW}⚠ 前端服务可能还在启动中${NC}" +fi + +# Test API endpoint +echo -e "${YELLOW}测试API端点...${NC}" +API_TEST_RESULT=$(curl -s -X GET "http://localhost:6002/search?q=test&size=5" 2>/dev/null | python -c " +import json +import sys +try: + data = json.load(sys.stdin) + if 'results' in data and len(data['results']) > 0: + print('API_TEST_OK') + else: + print('API_TEST_EMPTY') +except: + print('API_TEST_ERROR') +" 2>/dev/null || echo "API_TEST_ERROR") + +case $API_TEST_RESULT in + "API_TEST_OK") + echo -e "${GREEN}✓ API测试通过,返回搜索结果${NC}" + ;; + "API_TEST_EMPTY") + echo -e "${YELLOW}⚠ API测试通过,但返回空结果${NC}" + ;; + *) + echo -e "${YELLOW}⚠ API测试失败,服务可能还在启动中${NC}" + ;; +esac + +echo -e "${GREEN}========================================${NC}" +echo -e "${GREEN}完整测试流程结束!${NC}" +echo -e "${GREEN}========================================${NC}" +echo "" +echo -e "服务状态:" +echo -e " ${GREEN}前端界面: http://localhost:6003${NC}" +echo -e " ${GREEN}后端API: http://localhost:6002${NC}" +echo -e " ${GREEN}API文档: http://localhost:6002/docs${NC}" +echo "" +echo -e "可用脚本:" +echo -e " ${YELLOW}./run.sh${NC} - 仅启动服务(不导入数据)" +echo -e " ${YELLOW}./stop.sh${NC} - 停止所有服务" +echo -e " ${YELLOW}./restart.sh${NC} - 重启所有服务" +echo -e " ${YELLOW}./test_all.sh${NC}- 完整测试(包含数据导入)" +echo "" \ No newline at end of file diff --git a/test_cleaned_api.py b/test_cleaned_api.py deleted file mode 100644 index 90d7e01..0000000 --- a/test_cleaned_api.py +++ /dev/null @@ -1,143 +0,0 @@ -#!/usr/bin/env python3 -""" -测试清理后的API行为 -验证用户不再需要传递enable_translation等参数 -""" - -import sys -import os - -sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) - -def test_cleaned_api(): - """测试清理后的API行为""" - print("🧪 测试清理后的API行为") - print("=" * 60) - - try: - from api.models import SearchRequest - from search.searcher import Searcher - from config.config_loader import ConfigLoader - from context.request_context import create_request_context - - # 测试API模型不再包含内部参数 - print("📝 测试API模型...") - - # 创建搜索请求 - search_request = SearchRequest( - query="消防", - size=10, - from_=0, - filters=None, - min_score=None - ) - - print(f"✅ SearchRequest创建成功:") - print(f" - query: {search_request.query}") - print(f" - size: {search_request.size}") - print(f" - from_: {search_request.from_}") - print(f" - filters: {search_request.filters}") - print(f" - min_score: {search_request.min_score}") - - # 验证不再包含内部参数 - print(f"\n🚫 验证内部参数已移除:") - internal_params = ['enable_translation', 'enable_embedding', 'enable_rerank'] - for param in internal_params: - if hasattr(search_request, param): - print(f" ❌ {param} 仍然存在") - return False - else: - print(f" ✅ {param} 已移除") - - # 测试搜索器使用配置默认值 - print(f"\n🔧 测试搜索器使用配置默认值...") - - loader = ConfigLoader() - config = loader.load_customer_config("customer1") - - print(f"✅ 配置默认值:") - print(f" - enable_translation: {config.query_config.enable_translation}") - print(f" - enable_text_embedding: {config.query_config.enable_text_embedding}") - - # 创建模拟搜索器测试 - class MockESClient: - def search(self, **kwargs): - return { - "hits": {"hits": [], "total": {"value": 0}, "max_score": 0.0}, - "took": 15 - } - - es_client = MockESClient() - searcher = Searcher(config, es_client) - - # 测试搜索器方法签名 - import inspect - search_signature = inspect.signature(searcher.search) - search_params = list(search_signature.parameters.keys()) - - print(f"\n📋 搜索器方法参数:") - for param in search_params: - print(f" - {param}") - - # 验证不再包含内部参数 - print(f"\n🚫 验证搜索器参数已清理:") - for param in internal_params: - if param in search_params: - print(f" ❌ {param} 仍然存在") - return False - else: - print(f" ✅ {param} 已移除") - - # 测试实际的搜索调用 - print(f"\n🧪 测试实际搜索调用...") - context = create_request_context("cleaned_api_test", "test_user") - - result = searcher.search( - query="消防", - size=10, - from_=0, - filters=None, - min_score=None, - context=context - ) - - print(f"✅ 搜索调用成功!") - print(f" - 返回结果类型: {type(result).__name__}") - print(f" - 总命中数: {result.total}") - - # 检查上下文中的功能标志 - feature_flags = context.metadata.get('feature_flags', {}) - print(f"\n🚩 实际使用的功能标志:") - for flag, value in feature_flags.items(): - print(f" - {flag}: {value}") - - # 验证使用了配置默认值 - expected_translation = config.query_config.enable_translation - expected_embedding = config.query_config.enable_text_embedding - - actual_translation = feature_flags.get('translation_enabled') - actual_embedding = feature_flags.get('embedding_enabled') - - print(f"\n📊 功能验证:") - print(f" 翻译功能: 期望={expected_translation}, 实际={actual_translation} {'✅' if expected_translation == actual_translation else '❌'}") - print(f" 向量功能: 期望={expected_embedding}, 实际={actual_embedding} {'✅' if expected_embedding == actual_embedding else '❌'}") - - if expected_translation == actual_translation and expected_embedding == actual_embedding: - print(f"\n🎉 API清理成功!") - print(f"✅ 用户不再需要传递内部参数") - print(f"✅ 后端自动使用配置默认值") - print(f"✅ 功能完全透明") - return True - else: - print(f"\n⚠️ 功能验证失败") - return False - - except Exception as e: - print(f"❌ 测试失败: {e}") - import traceback - traceback.print_exc() - return False - -if __name__ == "__main__": - success = test_cleaned_api() - sys.exit(0 if success else 1) \ No newline at end of file diff --git a/test_context.py b/test_context.py deleted file mode 100644 index 084f626..0000000 --- a/test_context.py +++ /dev/null @@ -1,136 +0,0 @@ -""" -测试RequestContext功能的简单脚本 -""" - -import sys -import os - -# 添加项目根目录到Python路径 -sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) - -from context import RequestContext, RequestContextStage, create_request_context - - -def test_basic_context_functionality(): - """测试基本的context功能""" - print("=== 测试基本RequestContext功能 ===") - - # 创建context - context = create_request_context("test123", "user456") - - print(f"Request ID: {context.reqid}") - print(f"User ID: {context.uid}") - - # 测试阶段计时 - context.start_stage(RequestContextStage.QUERY_PARSING) - import time - time.sleep(0.1) # 模拟工作 - duration = context.end_stage(RequestContextStage.QUERY_PARSING) - - print(f"查询解析阶段耗时: {duration:.2f}ms") - - # 测试存储查询分析结果 - context.store_query_analysis( - original_query="iphone 13", - normalized_query="iphone 13", - rewritten_query="apple iphone 13", - detected_language="en" - ) - - # 测试存储中间结果 - context.store_intermediate_result('test_key', {'test': 'value'}) - - # 获取摘要 - summary = context.get_summary() - print("Context摘要:") - print(f" - 原始查询: {summary['query_analysis']['original_query']}") - print(f" - 检测语言: {summary['query_analysis']['detected_language']}") - print(f" - 阶段耗时: {summary['performance']['stage_timings_ms']}") - - print("✅ 基本功能测试通过\n") - - -def test_context_as_context_manager(): - """测试context作为上下文管理器的功能""" - print("=== 测试上下文管理器功能 ===") - - # 使用上下文管理器 - with create_request_context("cm123", "user789") as context: - context.start_stage(RequestContextStage.QUERY_PARSING) - import time - time.sleep(0.05) - context.end_stage(RequestContextStage.QUERY_PARSING) - - context.start_stage(RequestContextStage.QUERY_BUILDING) - time.sleep(0.03) - context.end_stage(RequestContextStage.QUERY_BUILDING) - - print(f"Context ID: {context.reqid}") - - # 退出时会自动记录性能摘要 - print("✅ 上下文管理器测试通过\n") - - -def test_error_handling(): - """测试错误处理功能""" - print("=== 测试错误处理功能 ===") - - context = create_request_context("error123") - - # 设置错误 - try: - raise ValueError("这是一个测试错误") - except Exception as e: - context.set_error(e) - - print(f"有错误: {context.has_error()}") - print(f"错误信息: {context.metadata['error_info']}") - - print("✅ 错误处理测试通过\n") - - -def test_performance_summary(): - """测试性能摘要功能""" - print("=== 测试性能摘要功能 ===") - - context = create_request_context("perf123") - - # 模拟多个阶段 - stages = [ - RequestContextStage.QUERY_PARSING, - RequestContextStage.BOOLEAN_PARSING, - RequestContextStage.QUERY_BUILDING, - RequestContextStage.ELASTICSEARCH_SEARCH, - RequestContextStage.RESULT_PROCESSING - ] - - import time - durations = [50, 20, 80, 150, 30] # 模拟各阶段耗时(ms) - - for stage, expected_duration in zip(stages, durations): - context.start_stage(stage) - time.sleep(expected_duration / 1000.0) # 转换为秒 - context.end_stage(stage) - - # 设置总耗时 - context.performance_metrics.total_duration = sum(durations) - - # 计算百分比 - percentages = context.calculate_stage_percentages() - - print("各阶段耗时占比:") - for stage, percentage in percentages.items(): - print(f" - {stage}: {percentage}%") - - print("✅ 性能摘要测试通过\n") - - -if __name__ == "__main__": - print("开始测试RequestContext功能...\n") - - test_basic_context_functionality() - test_context_as_context_manager() - test_error_handling() - test_performance_summary() - - print("🎉 所有测试通过!RequestContext功能正常。") \ No newline at end of file diff --git a/test_default_features.py b/test_default_features.py deleted file mode 100644 index c9bc738..0000000 --- a/test_default_features.py +++ /dev/null @@ -1,106 +0,0 @@ -#!/usr/bin/env python3 -""" -测试默认功能是否正确开启 -""" - -import sys -import os - -sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) - -def test_default_features(): - """测试默认功能是否正确开启""" - print("🧪 测试默认功能开启状态") - print("=" * 60) - - try: - from config.config_loader import ConfigLoader - from search.searcher import Searcher - from utils.es_client import ESClient - from context.request_context import create_request_context - - # 加载配置 - print("📝 加载配置...") - loader = ConfigLoader() - config = loader.load_customer_config("customer1") - - print(f"✅ 配置文件设置:") - print(f" - enable_translation: {config.query_config.enable_translation}") - print(f" - enable_text_embedding: {config.query_config.enable_text_embedding}") - - # 创建搜索器(模拟没有ES连接的情况) - print(f"\n🔍 创建搜索器...") - - # 创建一个模拟的ES客户端用于测试 - class MockESClient: - def search(self, **kwargs): - return { - "hits": {"hits": [], "total": {"value": 0}, "max_score": 0.0}, - "took": 10 - } - - es_client = MockESClient() - searcher = Searcher(config, es_client) - - # 测试不同参数组合 - test_cases = [ - {"name": "不传递任何参数", "params": {}}, - {"name": "显式传递None", "params": {"enable_translation": None, "enable_embedding": None}}, - {"name": "显式传递False", "params": {"enable_translation": False, "enable_embedding": False}}, - {"name": "显式传递True", "params": {"enable_translation": True, "enable_embedding": True}}, - ] - - print(f"\n🧪 测试不同参数组合:") - for test_case in test_cases: - print(f"\n 📋 {test_case['name']}:") - - try: - # 执行搜索 - result = searcher.search( - query="推车", - context=create_request_context("test_features", "test_user"), - **test_case['params'] - ) - - # 检查上下文中的功能标志 - context_summary = create_request_context("test_features", "test_user").get_summary() - # 由于我们无法直接获取内部的context,我们检查配置 - print(f" ✅ 搜索执行成功") - - except Exception as e: - print(f" ❌ 搜索失败: {e}") - - # 测试配置驱动的默认行为 - print(f"\n🔧 配置驱动的默认行为测试:") - - # 模拟API调用(不传递参数,应该使用配置默认值) - context = create_request_context("config_default_test", "config_user") - - print(f" 配置默认值:") - print(f" - 翻译功能: {'启用' if config.query_config.enable_translation else '禁用'}") - print(f" - 向量功能: {'启用' if config.query_config.enable_text_embedding else '禁用'}") - - # 验证配置逻辑 - expected_translation = config.query_config.enable_translation - expected_embedding = config.query_config.enable_text_embedding - - print(f"\n✅ 预期行为:") - print(f" 当API调用不传递enable_translation参数时,应该: {'启用翻译' if expected_translation else '禁用翻译'}") - print(f" 当API调用不传递enable_embedding参数时,应该: {'启用向量' if expected_embedding else '禁用向量'}") - - if expected_translation and expected_embedding: - print(f"\n🎉 配置正确!系统默认启用翻译和向量功能。") - return True - else: - print(f"\n⚠️ 配置可能需要调整。") - return False - - except Exception as e: - print(f"❌ 测试失败: {e}") - import traceback - traceback.print_exc() - return False - -if __name__ == "__main__": - success = test_default_features() - sys.exit(0 if success else 1) \ No newline at end of file diff --git a/test_fixed_query.py b/test_fixed_query.py deleted file mode 100644 index cc928eb..0000000 --- a/test_fixed_query.py +++ /dev/null @@ -1,127 +0,0 @@ -#!/usr/bin/env python3 -""" -测试修复后的查询解析功能 -验证翻译和向量生成是否正常工作 -""" - -import sys -import os - -sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) - -def test_fixed_query_parsing(): - """测试修复后的查询解析""" - print("🧪 测试修复后的查询解析功能") - print("=" * 60) - - try: - from context.request_context import create_request_context - from query.query_parser import QueryParser - from config import CustomerConfig - from config.config_loader import ConfigLoader - - # 加载配置 - print("📝 加载配置...") - loader = ConfigLoader() - config = loader.load_customer_config("customer1") - print(f"✅ 配置加载成功: {config.customer_id}") - print(f" - 翻译功能: {'启用' if config.query_config.enable_translation else '禁用'}") - print(f" - 向量功能: {'启用' if config.query_config.enable_text_embedding else '禁用'}") - - # 创建解析器和上下文 - parser = QueryParser(config) - context = create_request_context("test_fixed", "test_user") - - # 测试查询 - test_query = "推车" - print(f"\n🔍 测试查询: '{test_query}'") - - # 执行解析 - result = parser.parse( - test_query, - context=context, - generate_vector=config.query_config.enable_text_embedding - ) - - # 显示结果 - print(f"\n📊 查询解析结果:") - print(f" 原查询: {result.original_query}") - print(f" 标准化: {result.normalized_query}") - print(f" 重写后: {result.rewritten_query}") - print(f" 检测语言: {result.detected_language}") - print(f" 域: {result.domain}") - print(f" 翻译结果: {result.translations}") - - if result.query_vector is not None: - print(f" 向量: ✅ 已生成 (形状: {result.query_vector.shape})") - print(f" 向量类型: {type(result.query_vector)}") - print(f" 向量前5个值: {result.query_vector[:5]}") - else: - print(f" 向量: ❌ 未生成") - - # 检查翻译质量 - if result.translations: - print(f"\n🌍 翻译质量检查:") - for lang, translation in result.translations.items(): - if translation: - print(f" {lang}: '{translation}' ✅") - else: - print(f" {lang}: 翻译失败 ❌") - else: - print(f"\n🌍 翻译: 无翻译结果") - - # 测试上下文存储 - print(f"\n💾 上下文存储检查:") - stored_query = context.get_intermediate_result('normalized_query') - stored_lang = context.get_intermediate_result('detected_language') - stored_translations = context.get_intermediate_result('translations') - - print(f" 存储的查询: {stored_query}") - print(f" 存储的语言: {stored_lang}") - print(f" 存储的翻译: {stored_translations}") - - # 性能摘要 - summary = context.get_summary() - print(f"\n📈 性能摘要:") - print(f" 请求ID: {summary['request_info']['reqid']}") - print(f" 用户ID: {summary['request_info']['uid']}") - print(f" 有错误: {summary['request_info']['has_error']}") - print(f" 警告数量: {summary['request_info']['warnings_count']}") - print(f" 查询有向量: {summary['query_analysis']['has_vector']}") - - # 判断修复是否成功 - print(f"\n🎯 修复结果评估:") - - translation_success = ( - result.translations and - any(translation is not None and translation != result.original_query - for translation in result.translations.values()) - ) - - vector_success = result.query_vector is not None - - print(f" 翻译功能: {'✅ 修复成功' if translation_success else '❌ 仍有问题'}") - print(f" 向量功能: {'✅ 修复成功' if vector_success else '❌ 仍有问题'}") - - if translation_success and vector_success: - print(f"\n🎉 所有功能修复成功!") - return True - else: - print(f"\n⚠️ 还有功能需要修复") - return False - - except Exception as e: - print(f"❌ 测试失败: {e}") - import traceback - traceback.print_exc() - return False - -if __name__ == "__main__": - success = test_fixed_query_parsing() - - if success: - print(f"\n✨ 修复验证完成 - 系统正常运行!") - else: - print(f"\n💥 修复验证失败 - 需要进一步检查") - - sys.exit(0 if success else 1) \ No newline at end of file diff --git a/test_frontend_simulation.py b/test_frontend_simulation.py deleted file mode 100644 index c472da1..0000000 --- a/test_frontend_simulation.py +++ /dev/null @@ -1,142 +0,0 @@ -#!/usr/bin/env python3 -""" -模拟前端调用API -验证清理后的API对用户友好 -""" - -import sys -import os -import json - -sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) - -def simulate_frontend_call(): - """模拟前端API调用""" - print("🌐 模拟前端API调用") - print("=" * 60) - - try: - from api.models import SearchRequest - - print("📱 前端发送搜索请求...") - - # 模拟前端发送的请求(简洁明了) - frontend_request_data = { - "query": "芭比娃娃", - "size": 10, - "from_": 0, - "filters": { - "categoryName": "玩具" - } - } - - print(f"📤 请求数据:") - print(json.dumps(frontend_request_data, indent=2, ensure_ascii=False)) - - # 创建API请求对象 - search_request = SearchRequest(**frontend_request_data) - - print(f"\n✅ API请求创建成功!") - print(f" - 查询: '{search_request.query}'") - print(f" - 大小: {search_request.size}") - print(f" - 偏移: {search_request.from_}") - print(f" - 过滤器: {search_request.filters}") - - # 验证请求不包含内部参数 - internal_params = ['enable_translation', 'enable_embedding', 'enable_rerank'] - print(f"\n🔒 内部参数检查:") - for param in internal_params: - if hasattr(search_request, param): - print(f" ❌ {param}: 仍然暴露给用户") - return False - else: - print(f" ✅ {param}: 对用户透明") - - print(f"\n🎉 前端调用验证成功!") - print(f"✅ API接口简洁明了") - print(f"✅ 用户只需提供基本搜索参数") - print(f"✅ 复杂功能对用户完全透明") - print(f"✅ 后端自动处理翻译、向量搜索等功能") - - # 模拟响应结构 - print(f"\n📤 后端响应示例:") - response_example = { - "hits": [], - "total": 0, - "max_score": 0.0, - "took_ms": 45, - "aggregations": {}, - "query_info": { - "original_query": "芭比娃娃", - "rewritten_query": "brand:芭比 OR name:芭比娃娃娃娃", - "detected_language": "zh", - "translations": { - "en": "Barbie doll", - "ru": "кукла Барби" - } - }, - "performance_info": { - "request_info": { - "reqid": "abc123", - "has_error": False, - "warnings_count": 0 - }, - "performance": { - "total_duration_ms": 45.0, - "stage_timings_ms": { - "query_parsing": 25.0, - "boolean_parsing": 1.0, - "query_building": 2.0, - "elasticsearch_search": 10.0, - "result_processing": 1.0 - } - } - } - } - - print(json.dumps(response_example, indent=2, ensure_ascii=False)) - - return True - - except Exception as e: - print(f"❌ 模拟失败: {e}") - import traceback - traceback.print_exc() - return False - -def show_api_comparison(): - """显示清理前后的API对比""" - print(f"\n📊 API接口对比:") - print("=" * 60) - - print(f"❌ 清理前(暴露内部参数):") - print(json.dumps({ - "query": "芭比娃娃", - "size": 10, - "from_": 0, - "enable_translation": True, # ❌ 用户不需要关心 - "enable_embedding": True, # ❌ 用户不需要关心 - "enable_rerank": True, # ❌ 用户不需要关心 - "min_score": None - }, indent=2, ensure_ascii=False)) - - print(f"\n✅ 清理后(用户友好):") - print(json.dumps({ - "query": "芭比娃娃", - "size": 10, - "from_": 0, - "filters": {"categoryName": "玩具"}, - "min_score": None - }, indent=2, ensure_ascii=False)) - -if __name__ == "__main__": - success = simulate_frontend_call() - show_api_comparison() - - if success: - print(f"\n🎊 API清理完全成功!") - print(f"🌟 现在的API对用户非常友好!") - else: - print(f"\n💥 还有问题需要解决") - - sys.exit(0 if success else 1) \ No newline at end of file diff --git a/test_multilang_config.py b/test_multilang_config.py deleted file mode 100644 index 8452ddb..0000000 --- a/test_multilang_config.py +++ /dev/null @@ -1,155 +0,0 @@ -#!/usr/bin/env python3 -""" -Test script to validate multi-language configuration. - -This script validates that: -1. language_field_mapping is correctly loaded from config -2. All referenced fields exist and have correct analyzers -3. Multi-language query builder works correctly -""" - -import sys -import json -from config import ConfigLoader - -def test_config_loading(): - """Test that configuration loads correctly with language_field_mapping.""" - print("=" * 60) - print("Testing Configuration Loading") - print("=" * 60) - - try: - loader = ConfigLoader() - config = loader.load_customer_config('customer1') - - print(f"\n✓ Configuration loaded successfully") - print(f" Customer: {config.customer_name}") - print(f" ES Index: {config.es_index_name}") - - # Validate configuration - errors = loader.validate_config(config) - if errors: - print(f"\n✗ Configuration validation failed:") - for error in errors: - print(f" - {error}") - return False - else: - print(f"\n✓ Configuration validation passed") - - # Check indexes with language_field_mapping - print(f"\nIndexes with multi-language support:") - for index in config.indexes: - if index.language_field_mapping: - print(f"\n {index.name} ({index.label}):") - print(f" Fields: {index.fields}") - print(f" Language mapping:") - for lang, fields in index.language_field_mapping.items(): - print(f" {lang}: {fields}") - else: - print(f"\n {index.name} ({index.label}): No language mapping") - - return True - - except Exception as e: - print(f"\n✗ Error loading configuration: {e}") - import traceback - traceback.print_exc() - return False - - -def test_multilang_query_builder(): - """Test that MultiLanguageQueryBuilder works correctly.""" - print("\n" + "=" * 60) - print("Testing Multi-Language Query Builder") - print("=" * 60) - - try: - from config import ConfigLoader - from query import QueryParser - from search.multilang_query_builder import MultiLanguageQueryBuilder - from indexer import MappingGenerator - - loader = ConfigLoader() - config = loader.load_customer_config('customer1') - - # Initialize query builder - mapping_gen = MappingGenerator(config) - text_embedding_field = mapping_gen.get_text_embedding_field() - image_embedding_field = mapping_gen.get_image_embedding_field() - - query_builder = MultiLanguageQueryBuilder( - config=config, - index_name=config.es_index_name, - text_embedding_field=text_embedding_field, - image_embedding_field=image_embedding_field - ) - - print(f"\n✓ MultiLanguageQueryBuilder initialized") - - # Get domain summary - summary = query_builder.get_domain_summary() - print(f"\nDomain Summary:") - for domain, info in summary.items(): - print(f" {domain}:") - print(f" Label: {info['label']}") - print(f" Has multilang mapping: {info['has_multilang_mapping']}") - if info['has_multilang_mapping']: - print(f" Supported languages: {info['supported_languages']}") - - # Test query parsing - query_parser = QueryParser(config) - test_queries = [ - "芭比娃娃", - "title:芭比娃娃", - "default:玩具" - ] - - print(f"\nTesting query parsing:") - for query in test_queries: - print(f"\n Query: '{query}'") - parsed = query_parser.parse(query, generate_vector=False) - print(f" Domain: {parsed.domain}") - print(f" Detected language: {parsed.detected_language}") - print(f" Translations: {list(parsed.translations.keys())}") - - # Build query - es_query = query_builder.build_multilang_query( - parsed_query=parsed, - query_vector=None, - filters=None, - size=10, - enable_knn=False - ) - print(f" ES Query keys: {list(es_query.keys())}") - - return True - - except Exception as e: - print(f"\n✗ Error testing query builder: {e}") - import traceback - traceback.print_exc() - return False - - -if __name__ == "__main__": - print("Multi-Language Configuration Test") - print("=" * 60) - - success = True - - # Test 1: Configuration loading - if not test_config_loading(): - success = False - - # Test 2: Multi-language query builder - if not test_multilang_query_builder(): - success = False - - print("\n" + "=" * 60) - if success: - print("✓ All tests passed!") - sys.exit(0) - else: - print("✗ Some tests failed") - sys.exit(1) - diff --git a/test_search_integration.py b/test_search_integration.py deleted file mode 100644 index b1ac20f..0000000 --- a/test_search_integration.py +++ /dev/null @@ -1,80 +0,0 @@ -#!/usr/bin/env python3 -""" -测试搜索集成的自测脚本 -验证请求上下文和日志系统是否正常工作 -""" - -import sys -import os - -# 添加项目路径 -sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) - -def test_search_integration(): - """测试搜索集成""" - print("🧪 开始搜索集成自测...") - - try: - # 导入模块 - from context.request_context import create_request_context - from utils.logger import get_logger, setup_logging - - # 设置日志 - setup_logging(log_level="INFO", log_dir="test_logs") - logger = get_logger("test") - - print("✅ 模块导入成功") - - # 创建请求上下文 - context = create_request_context("test123", "testuser") - print(f"✅ 请求上下文创建成功: reqid={context.reqid}") - - # 测试日志记录 - context.logger.info("测试日志记录", extra={'reqid': context.reqid, 'uid': context.uid}) - print("✅ 日志记录正常") - - # 测试存储中间结果 - context.store_intermediate_result("test_query", "芭比娃娃") - context.store_intermediate_result("test_language", "zh") - print("✅ 中间结果存储正常") - - # 测试查询分析存储 - context.store_query_analysis( - original_query="芭比娃娃", - normalized_query="芭比娃娃", - rewritten_query="芭比娃娃", - detected_language="zh", - domain="default" - ) - print("✅ 查询分析存储正常") - - # 测试性能摘要 - context.log_performance_summary() - print("✅ 性能摘要记录正常") - - # 测试完整的上下文摘要 - summary = context.get_summary() - print(f"✅ 上下文摘要生成成功,包含 {len(str(summary))} 字符的数据") - - print("\n📊 测试摘要:") - print(f" 请求ID: {summary['request_info']['reqid']}") - print(f" 用户ID: {summary['request_info']['uid']}") - print(f" 查询: '{summary['query_analysis']['original_query']}'") - print(f" 语言: {summary['query_analysis']['detected_language']}") - - print("\n🎉 所有自测通过!搜索集成功能正常工作。") - return True - - except Exception as e: - print(f"❌ 自测失败: {e}") - import traceback - traceback.print_exc() - return False - -if __name__ == "__main__": - success = test_search_integration() - if success: - print("\n✨ 系统已就绪,可以正常处理搜索请求!") - else: - print("\n💥 请检查错误信息并修复问题") - sys.exit(1) \ No newline at end of file -- libgit2 0.21.2