good version for 算法注册
This commit is contained in:
Binary file not shown.
BIN
backend/app/services/__pycache__/config_service.cpython-312.pyc
Normal file
BIN
backend/app/services/__pycache__/config_service.cpython-312.pyc
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
165
backend/app/services/comparison_service.py
Normal file
165
backend/app/services/comparison_service.py
Normal file
@@ -0,0 +1,165 @@
|
||||
from typing import Dict, Any, List
|
||||
import asyncio
|
||||
import httpx
|
||||
import logging
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class ComparisonService:
|
||||
"""效果对比服务"""
|
||||
|
||||
async def compare_algorithms(
|
||||
self,
|
||||
input_data: Dict[str, Any],
|
||||
algorithm_configs: List[Dict[str, Any]]
|
||||
) -> Dict[str, Any]:
|
||||
"""比较多个算法的效果
|
||||
|
||||
Args:
|
||||
input_data: 输入数据
|
||||
algorithm_configs: 算法配置列表,每个配置包含服务URL、参数等
|
||||
|
||||
Returns:
|
||||
对比结果
|
||||
"""
|
||||
try:
|
||||
# 异步执行所有算法
|
||||
tasks = []
|
||||
for config in algorithm_configs:
|
||||
task = self._execute_algorithm(config, input_data)
|
||||
tasks.append(task)
|
||||
|
||||
results = await asyncio.gather(*tasks, return_exceptions=True)
|
||||
|
||||
# 处理结果
|
||||
comparison_results = []
|
||||
for i, result in enumerate(results):
|
||||
if isinstance(result, Exception):
|
||||
comparison_results.append({
|
||||
"algorithm_id": algorithm_configs[i].get("id"),
|
||||
"algorithm_name": algorithm_configs[i].get("name"),
|
||||
"success": False,
|
||||
"error": str(result),
|
||||
"output": None,
|
||||
"execution_time": 0
|
||||
})
|
||||
else:
|
||||
comparison_results.append({
|
||||
"algorithm_id": algorithm_configs[i].get("id"),
|
||||
"algorithm_name": algorithm_configs[i].get("name"),
|
||||
"success": True,
|
||||
"error": None,
|
||||
"output": result.get("output"),
|
||||
"execution_time": result.get("execution_time", 0)
|
||||
})
|
||||
|
||||
return {
|
||||
"success": True,
|
||||
"results": comparison_results,
|
||||
"input_data": input_data
|
||||
}
|
||||
except Exception as e:
|
||||
logger.error(f"Comparison error: {str(e)}")
|
||||
return {
|
||||
"success": False,
|
||||
"error": str(e),
|
||||
"results": []
|
||||
}
|
||||
|
||||
async def _execute_algorithm(
|
||||
self,
|
||||
config: Dict[str, Any],
|
||||
input_data: Dict[str, Any]
|
||||
) -> Dict[str, Any]:
|
||||
"""执行单个算法
|
||||
|
||||
Args:
|
||||
config: 算法配置
|
||||
input_data: 输入数据
|
||||
|
||||
Returns:
|
||||
执行结果
|
||||
"""
|
||||
import time
|
||||
start_time = time.time()
|
||||
|
||||
try:
|
||||
url = config.get("url")
|
||||
params = config.get("params", {})
|
||||
|
||||
if not url:
|
||||
raise ValueError("缺少算法服务URL")
|
||||
|
||||
# 构建请求数据
|
||||
request_data = {
|
||||
"input_data": input_data.get("input_data", input_data),
|
||||
"params": params
|
||||
}
|
||||
|
||||
# 发送请求
|
||||
async with httpx.AsyncClient(timeout=30.0) as client:
|
||||
response = await client.post(f"{url}/predict", json=request_data)
|
||||
response.raise_for_status()
|
||||
result = response.json()
|
||||
|
||||
execution_time = time.time() - start_time
|
||||
|
||||
return {
|
||||
"output": result,
|
||||
"execution_time": execution_time
|
||||
}
|
||||
except Exception as e:
|
||||
logger.error(f"Algorithm execution error: {str(e)}")
|
||||
raise e
|
||||
|
||||
def generate_comparison_report(self, comparison_results: Dict[str, Any]) -> Dict[str, Any]:
|
||||
"""生成对比报告
|
||||
|
||||
Args:
|
||||
comparison_results: 对比结果
|
||||
|
||||
Returns:
|
||||
对比报告
|
||||
"""
|
||||
try:
|
||||
if not comparison_results.get("success"):
|
||||
return {
|
||||
"success": False,
|
||||
"error": comparison_results.get("error", "对比失败")
|
||||
}
|
||||
|
||||
results = comparison_results.get("results", [])
|
||||
|
||||
# 分析结果
|
||||
successful_algorithms = [r for r in results if r.get("success")]
|
||||
failed_algorithms = [r for r in results if not r.get("success")]
|
||||
|
||||
# 计算平均执行时间
|
||||
if successful_algorithms:
|
||||
avg_execution_time = sum(r.get("execution_time", 0) for r in successful_algorithms) / len(successful_algorithms)
|
||||
else:
|
||||
avg_execution_time = 0
|
||||
|
||||
# 生成报告
|
||||
report = {
|
||||
"summary": {
|
||||
"total_algorithms": len(results),
|
||||
"successful_algorithms": len(successful_algorithms),
|
||||
"failed_algorithms": len(failed_algorithms),
|
||||
"average_execution_time": round(avg_execution_time, 2)
|
||||
},
|
||||
"details": results,
|
||||
"input_data": comparison_results.get("input_data")
|
||||
}
|
||||
|
||||
return {
|
||||
"success": True,
|
||||
"report": report
|
||||
}
|
||||
except Exception as e:
|
||||
logger.error(f"Report generation error: {str(e)}")
|
||||
return {
|
||||
"success": False,
|
||||
"error": str(e)
|
||||
}
|
||||
165
backend/app/services/config_service.py
Normal file
165
backend/app/services/config_service.py
Normal file
@@ -0,0 +1,165 @@
|
||||
from typing import Optional, Dict, Any, List
|
||||
from sqlalchemy.orm import Session
|
||||
from app.models.models import ServiceConfig
|
||||
import uuid
|
||||
import logging
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class ConfigService:
|
||||
"""配置服务"""
|
||||
|
||||
@staticmethod
|
||||
def get_config(db: Session, config_key: str) -> Optional[Dict[str, Any]]:
|
||||
"""获取配置
|
||||
|
||||
Args:
|
||||
db: 数据库会话
|
||||
config_key: 配置键
|
||||
|
||||
Returns:
|
||||
配置值,如果不存在返回None
|
||||
"""
|
||||
config = db.query(ServiceConfig).filter_by(
|
||||
config_key=config_key,
|
||||
status="active"
|
||||
).first()
|
||||
|
||||
if config:
|
||||
return config.config_value
|
||||
return None
|
||||
|
||||
@staticmethod
|
||||
def set_config(db: Session, config_key: str, config_value: Dict[str, Any],
|
||||
config_type: str = "system", service_id: Optional[str] = None,
|
||||
description: str = "") -> bool:
|
||||
"""设置配置
|
||||
|
||||
Args:
|
||||
db: 数据库会话
|
||||
config_key: 配置键
|
||||
config_value: 配置值
|
||||
config_type: 配置类型,默认为"system"
|
||||
service_id: 服务ID,系统配置可为None
|
||||
description: 配置描述
|
||||
|
||||
Returns:
|
||||
是否设置成功
|
||||
"""
|
||||
try:
|
||||
# 检查是否存在
|
||||
existing_config = db.query(ServiceConfig).filter_by(
|
||||
config_key=config_key
|
||||
).first()
|
||||
|
||||
if existing_config:
|
||||
# 更新现有配置
|
||||
existing_config.config_value = config_value
|
||||
existing_config.config_type = config_type
|
||||
existing_config.service_id = service_id
|
||||
existing_config.description = description
|
||||
existing_config.status = "active"
|
||||
else:
|
||||
# 创建新配置
|
||||
new_config = ServiceConfig(
|
||||
id=f"config-{uuid.uuid4()}",
|
||||
config_key=config_key,
|
||||
config_value=config_value,
|
||||
config_type=config_type,
|
||||
service_id=service_id,
|
||||
description=description,
|
||||
status="active"
|
||||
)
|
||||
db.add(new_config)
|
||||
|
||||
db.commit()
|
||||
return True
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to set config: {str(e)}")
|
||||
db.rollback()
|
||||
return False
|
||||
|
||||
@staticmethod
|
||||
def get_service_configs(db: Session, service_id: str) -> List[Dict[str, Any]]:
|
||||
"""获取服务的所有配置
|
||||
|
||||
Args:
|
||||
db: 数据库会话
|
||||
service_id: 服务ID
|
||||
|
||||
Returns:
|
||||
服务配置列表
|
||||
"""
|
||||
configs = db.query(ServiceConfig).filter_by(
|
||||
service_id=service_id,
|
||||
status="active"
|
||||
).all()
|
||||
|
||||
return [
|
||||
{
|
||||
"key": config.config_key,
|
||||
"value": config.config_value,
|
||||
"type": config.config_type,
|
||||
"description": config.description
|
||||
}
|
||||
for config in configs
|
||||
]
|
||||
|
||||
@staticmethod
|
||||
def delete_config(db: Session, config_key: str) -> bool:
|
||||
"""删除配置
|
||||
|
||||
Args:
|
||||
db: 数据库会话
|
||||
config_key: 配置键
|
||||
|
||||
Returns:
|
||||
是否删除成功
|
||||
"""
|
||||
try:
|
||||
config = db.query(ServiceConfig).filter_by(
|
||||
config_key=config_key
|
||||
).first()
|
||||
|
||||
if config:
|
||||
config.status = "inactive"
|
||||
db.commit()
|
||||
|
||||
return True
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to delete config: {str(e)}")
|
||||
db.rollback()
|
||||
return False
|
||||
|
||||
@staticmethod
|
||||
def get_all_configs(db: Session, config_type: Optional[str] = None) -> List[Dict[str, Any]]:
|
||||
"""获取所有配置
|
||||
|
||||
Args:
|
||||
db: 数据库会话
|
||||
config_type: 配置类型,可选
|
||||
|
||||
Returns:
|
||||
配置列表
|
||||
"""
|
||||
query = db.query(ServiceConfig).filter_by(status="active")
|
||||
|
||||
if config_type:
|
||||
query = query.filter_by(config_type=config_type)
|
||||
|
||||
configs = query.all()
|
||||
|
||||
return [
|
||||
{
|
||||
"id": config.id,
|
||||
"key": config.config_key,
|
||||
"value": config.config_value,
|
||||
"type": config.config_type,
|
||||
"service_id": config.service_id,
|
||||
"description": config.description,
|
||||
"created_at": config.created_at,
|
||||
"updated_at": config.updated_at
|
||||
}
|
||||
for config in configs
|
||||
]
|
||||
@@ -63,22 +63,41 @@ class ProjectAnalyzer:
|
||||
Returns:
|
||||
项目类型,如 "python", "java", "nodejs" 等
|
||||
"""
|
||||
# 检查Python项目
|
||||
# 检查Python项目 - 先检查根目录
|
||||
if os.path.exists(os.path.join(repo_path, "requirements.txt")) or \
|
||||
os.path.exists(os.path.join(repo_path, "pyproject.toml")) or \
|
||||
any(file.endswith(".py") for file in os.listdir(repo_path)):
|
||||
return "python"
|
||||
|
||||
# 检查Java项目
|
||||
# 检查Python项目 - 递归检查子目录
|
||||
for root, dirs, files in os.walk(repo_path):
|
||||
if "requirements.txt" in files or "pyproject.toml" in files:
|
||||
return "python"
|
||||
if any(file.endswith(".py") for file in files):
|
||||
return "python"
|
||||
|
||||
# 检查Java项目 - 先检查根目录
|
||||
if os.path.exists(os.path.join(repo_path, "pom.xml")) or \
|
||||
os.path.exists(os.path.join(repo_path, "build.gradle")) or \
|
||||
os.path.exists(os.path.join(repo_path, "src")):
|
||||
return "java"
|
||||
|
||||
# 检查Node.js项目
|
||||
# 检查Java项目 - 递归检查子目录
|
||||
for root, dirs, files in os.walk(repo_path):
|
||||
if "pom.xml" in files or "build.gradle" in files:
|
||||
return "java"
|
||||
if "src" in dirs:
|
||||
return "java"
|
||||
|
||||
# 检查Node.js项目 - 先检查根目录
|
||||
if os.path.exists(os.path.join(repo_path, "package.json")):
|
||||
return "nodejs"
|
||||
|
||||
# 检查Node.js项目 - 递归检查子目录
|
||||
for root, dirs, files in os.walk(repo_path):
|
||||
if "package.json" in files:
|
||||
return "nodejs"
|
||||
|
||||
# 检查其他项目类型
|
||||
if os.path.exists(os.path.join(repo_path, "CMakeLists.txt")):
|
||||
return "c++"
|
||||
|
||||
@@ -38,13 +38,14 @@ class ServiceOrchestrator:
|
||||
self.client = None
|
||||
print("使用本地进程部署模式")
|
||||
|
||||
def deploy_service(self, service_id: str, service_config: Dict[str, Any], project_info: Dict[str, Any]) -> Dict[str, Any]:
|
||||
def deploy_service(self, service_id: str, service_config: Dict[str, Any], project_info: Dict[str, Any], repo_path: str = None) -> Dict[str, Any]:
|
||||
"""部署服务
|
||||
|
||||
Args:
|
||||
service_id: 服务ID
|
||||
service_config: 服务配置
|
||||
project_info: 项目信息
|
||||
repo_path: 仓库路径(用于复制真实的算法文件)
|
||||
|
||||
Returns:
|
||||
部署结果
|
||||
@@ -95,7 +96,7 @@ class ServiceOrchestrator:
|
||||
service_dir = self._create_service_directory(service_id)
|
||||
|
||||
# 2. 生成服务包装器
|
||||
self._generate_local_service_wrapper(service_dir, project_info, service_config)
|
||||
self._generate_local_service_wrapper(service_dir, project_info, service_config, repo_path)
|
||||
|
||||
# 3. 启动服务进程
|
||||
process_info = self._start_local_service_process(service_id, service_dir, project_info, service_config)
|
||||
@@ -176,9 +177,13 @@ class ServiceOrchestrator:
|
||||
else:
|
||||
# 本地进程启动
|
||||
if service_id not in self.processes:
|
||||
# 服务不在进程列表中,可能是服务重启导致的
|
||||
# 这种情况下,需要从外部重新注册服务
|
||||
# 暂时返回错误,建议用户重新注册服务
|
||||
print(f"服务 {service_id} 不在进程列表中,无法启动")
|
||||
return {
|
||||
"success": False,
|
||||
"error": "服务不存在",
|
||||
"error": "服务不存在,请重新注册服务",
|
||||
"service_id": service_id,
|
||||
"status": "error"
|
||||
}
|
||||
@@ -272,11 +277,18 @@ class ServiceOrchestrator:
|
||||
else:
|
||||
# 本地进程停止
|
||||
if service_id not in self.processes:
|
||||
# 服务不在进程列表中,可能是服务重启导致的
|
||||
# 尝试通过端口查找并停止进程
|
||||
print(f"服务 {service_id} 不在进程列表中,尝试通过端口查找进程")
|
||||
|
||||
# 从服务配置中获取端口信息
|
||||
# 这里需要从外部传入服务配置,或者从数据库查询
|
||||
# 暂时返回成功,因为服务可能已经停止了
|
||||
return {
|
||||
"success": False,
|
||||
"error": "服务不存在",
|
||||
"success": True,
|
||||
"service_id": service_id,
|
||||
"status": "error"
|
||||
"status": "stopped",
|
||||
"error": None
|
||||
}
|
||||
|
||||
process_info = self.processes[service_id]
|
||||
@@ -1271,13 +1283,14 @@ json
|
||||
os.makedirs(service_dir, exist_ok=True)
|
||||
return service_dir
|
||||
|
||||
def _generate_local_service_wrapper(self, service_dir: str, project_info: Dict[str, Any], service_config: Dict[str, Any]):
|
||||
def _generate_local_service_wrapper(self, service_dir: str, project_info: Dict[str, Any], service_config: Dict[str, Any], repo_path: str = None):
|
||||
"""生成本地服务包装器
|
||||
|
||||
Args:
|
||||
service_dir: 服务目录
|
||||
project_info: 项目信息
|
||||
service_config: 服务配置
|
||||
repo_path: 仓库路径(用于复制真实的算法文件)
|
||||
"""
|
||||
# 生成服务包装器
|
||||
service_wrapper_content = self._generate_service_wrapper(project_info, service_config)
|
||||
@@ -1285,7 +1298,44 @@ json
|
||||
with open(os.path.join(service_dir, f"service_wrapper{wrapper_extension}"), "w") as f:
|
||||
f.write(service_wrapper_content)
|
||||
|
||||
# 创建模拟的算法文件
|
||||
# 复制真实的算法文件
|
||||
if repo_path and project_info["project_type"] == "python":
|
||||
# 尝试找到并复制主要的算法文件
|
||||
entry_point = project_info.get("entry_point")
|
||||
if entry_point:
|
||||
source_file = os.path.join(repo_path, entry_point)
|
||||
if os.path.exists(source_file):
|
||||
# 复制算法文件到服务目录
|
||||
import shutil
|
||||
shutil.copy2(source_file, os.path.join(service_dir, "algorithm.py"))
|
||||
print(f"已复制算法文件: {source_file} -> {os.path.join(service_dir, 'algorithm.py')}")
|
||||
return
|
||||
|
||||
# 如果没有找到入口点,尝试复制所有Python文件
|
||||
if os.path.exists(repo_path):
|
||||
import shutil
|
||||
for root, dirs, files in os.walk(repo_path):
|
||||
for file in files:
|
||||
if file.endswith(".py") and not file.startswith("_"):
|
||||
source_file = os.path.join(root, file)
|
||||
dest_file = os.path.join(service_dir, file)
|
||||
shutil.copy2(source_file, dest_file)
|
||||
print(f"已复制Python文件: {source_file} -> {dest_file}")
|
||||
|
||||
# 如果有algorithm.py,就使用它,否则创建一个模拟的
|
||||
if not os.path.exists(os.path.join(service_dir, "algorithm.py")):
|
||||
print("未找到algorithm.py,创建模拟算法文件")
|
||||
self._create_mock_algorithm(service_dir)
|
||||
else:
|
||||
# 创建模拟的算法文件
|
||||
self._create_mock_algorithm(service_dir)
|
||||
|
||||
def _create_mock_algorithm(self, service_dir: str):
|
||||
"""创建模拟的算法文件
|
||||
|
||||
Args:
|
||||
service_dir: 服务目录
|
||||
"""
|
||||
algorithm_content = """
|
||||
def predict(data):
|
||||
return {"result": "Prediction result", "input": data}
|
||||
@@ -1316,9 +1366,9 @@ def main(data):
|
||||
|
||||
# 构建启动命令
|
||||
if project_info["project_type"] == "python":
|
||||
cmd = ["python", f"service_wrapper.py"]
|
||||
cmd = ["python", "service_wrapper.py"]
|
||||
else:
|
||||
cmd = ["node", f"service_wrapper.js"]
|
||||
cmd = ["node", "service_wrapper.js"]
|
||||
|
||||
# 设置环境变量
|
||||
env = os.environ.copy()
|
||||
|
||||
Reference in New Issue
Block a user