Files
algorithm/多独立服务管理实施方案.md

63 KiB
Raw Blame History

多独立 AI 算法服务管理实施方案

1. 方案概述

本方案旨在解决多 AI 算法服务的端口冲突、统一启停/监控、配置管理和运维效率问题,同时保持每个服务的独立性,避免单个服务故障影响其他服务。方案支持两种部署方式:无 Docker 的实现方式(使用 Supervisor和 Docker 容器化实现方式,通过「标准化 + 统一管理」的方法,实现多服务的高效管理。

本方案专门为 AI 算法工程展示平台设计,支持从代码上传、服务部署到算法能力展示的完整流程,满足用户对算法工程管理和展示的核心需求。

1.1 核心诉求

  • 端口冲突:为每个服务分配唯一端口,避免冲突
  • 统一管理:批量管理所有服务的启停、监控、自动重启
  • 配置管理:集中化管理公共配置,保留服务独立配置,包括 Gitea 访问配置
  • 运维效率:降低运维成本,提高服务可靠性
  • 服务独立性:单个服务故障不影响其他服务
  • 代码管理:集成 Gitea 进行代码管理和部署,支持算法工程代码上传
  • 服务部署:自动部署算法工程为 API 服务
  • 算法展示:支持使用演示数据和视频执行算法,展示算法能力
  • 效果对比:支持对比不同算法或参数的效果

1.2 技术栈

  • 服务运行Python/Node.js + FastAPI/HTTP Server
  • 统一管理Supervisor
  • 可选NginxAPI 网关)
  • 监控:服务健康检查 + 日志管理
  • 数据库PostgreSQL
  • 缓存Redis
  • 对象存储MinIO
  • 代码管理Gitea
  • 前端Vue 3 + TypeScript + Vite + Element Plus
  • 后端FastAPI

1.3 网站用途与工作流程

本网站的核心用途是展示和管理多个 AI 算法工程,通过以下三个步骤实现:

第一步:代码管理

  • 上传 AI 算法工程代码到平台
  • 将代码管理在 Gitea 仓库中
  • Gitea 访问配置保存在数据库中,确保配置持久化

第二步:服务部署与管理

  • 部署上传的算法工程为可访问的 API 服务
  • 支持多服务的统一管理(启动、停止、重启)
  • 生成标准化的 API 接口
  • 监控服务健康状态和运行情况

第三步:算法能力展示

  • 使用演示数据和视频等输入执行算法
  • 可视化展示算法执行结果
  • 对比不同算法或参数的效果
  • 向客户展示 AI 算法的能力和价值

2. 项目架构分析

2.1 系统架构

┌─────────────────────────────────────────────────────────┐
│                    前端层                              │
│  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐     │
│  │ Vue 3       │  │ TypeScript  │  │ Element Plus│     │
│  └─────────────┘  └─────────────┘  └─────────────┘     │
├─────────────────────────────────────────────────────────┤
│                    后端层                              │
│  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐     │
│  │ FastAPI     │  │ Service     │  │ Gitea       │     │
│  │             │  │ Orchestrator│  │ Integration │     │
│  └─────────────┘  └─────────────┘  └─────────────┘     │
├─────────────────────────────────────────────────────────┤
│                    服务层                              │
│  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐     │
│  │ Service-1   │  │ Service-2   │  │ Service-3   │     │
│  │ 端口: 8001  │  │ 端口: 8002  │  │ 端口: 8003  │     │
│  └─────────────┘  └─────────────┘  └─────────────┘     │
├─────────────────────────────────────────────────────────┤
│                    存储层                              │
│  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐     │
│  │ PostgreSQL  │  │ Redis       │  │ MinIO       │     │
│  └─────────────┘  └─────────────┘  └─────────────┘     │
└─────────────────────────────────────────────────────────┘

2.2 现有系统功能

  • 服务部署(支持 Docker 和本地进程)
  • 服务启动/停止/重启/删除
  • 服务状态查询
  • 服务日志获取
  • 服务健康检查
  • Gitea 集成(代码管理和部署)
  • 数据库配置管理
  • 前端管理界面

2.3 现有实现的优缺点

优点

  • 支持两种部署模式,灵活性高
  • 提供完整的服务生命周期管理
  • 实现了服务健康检查和日志管理
  • 集成了 Gitea 进行代码管理和部署
  • 支持数据库配置管理
  • 提供了完整的前端管理界面

缺点

  • 本地进程模式下,服务管理依赖于 ServiceOrchestrator 进程,进程退出后无法自动管理服务
  • 缺乏批量管理能力,每次操作需要单独处理每个服务
  • 服务配置分散,缺乏集中化管理
  • 端口管理依赖手动配置,容易冲突

3. 方案设计

3.1 整体架构

┌─────────────────────────────────────────────────────────┐
│                    管理层                              │
│  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐     │
│  │ Supervisor  │  │   Nginx     │  │  配置管理   │     │
│  └─────────────┘  └─────────────┘  └─────────────┘     │
├─────────────────────────────────────────────────────────┤
│                    服务层                              │
│  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐     │
│  │ Service-1   │  │ Service-2   │  │ Service-3   │     │
│  │ 端口: 8001  │  │ 端口: 8002  │  │ 端口: 8003  │     │
│  └─────────────┘  └─────────────┘  └─────────────┘     │
├─────────────────────────────────────────────────────────┤
│                    基础设施层                           │
│  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐     │
│  │ 操作系统    │  │ 网络        │  │ 文件系统    │     │
│  └─────────────┘  └─────────────┘  └─────────────┘     │
└─────────────────────────────────────────────────────────┘

3.2 核心设计原则

  1. 服务标准化:统一目录结构、接口规范、启动方式
  2. 端口独占规划:为每个服务分配唯一端口
  3. 统一管理工具:使用 Supervisor 批量管理服务
  4. 配置集中化:抽离公共配置,保留独立配置
  5. 服务独立性:每个服务独立运行,独立管理
  6. 代码管理集成:通过 Gitea 管理服务代码和部署

4. 分步实现

4.1 第一步:数据库配置管理

4.1.1 配置存储架构

为了支持在界面上配置并存储到数据库中,我们需要设计一个统一的配置管理架构:

┌─────────────────────────────────────────────────────────┐
│                    配置管理架构                         │
├─────────────────────────────────────────────────────────┤
│  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐     │
│  │ 前端配置界面 │  │ 配置API层   │  │ 配置服务层  │     │
│  └─────────────┘  └─────────────┘  └─────────────┘     │
├─────────────────────────────────────────────────────────┤
│  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐     │
│  │ 配置数据库  │  │ 缓存层      │  │ 配置文件    │     │
│  └─────────────┘  └─────────────┘  └─────────────┘     │
└─────────────────────────────────────────────────────────┘

4.1.2 配置数据库模型

创建统一的配置存储模型:

# backend/app/models/models.py

class ServiceConfig(Base):
    """服务配置模型"""
    __tablename__ = "service_configs"
    
    id = Column(String, primary_key=True, index=True)
    config_key = Column(String, nullable=False, unique=True, index=True)  # 配置键
    config_value = Column(JSON, nullable=False)  # 配置值JSON格式
    config_type = Column(String, nullable=False)  # 配置类型system, service, user
    service_id = Column(String, nullable=True, index=True)  # 服务ID可为空系统配置
    description = Column(Text, default="")  # 配置描述
    status = Column(String, default="active")  # 状态
    created_at = Column(DateTime(timezone=True), server_default=func.now())
    updated_at = Column(DateTime(timezone=True), onupdate=func.now())

4.1.3 配置服务实现

# backend/app/services/config_service.py

class ConfigService:
    """配置服务"""
    
    @staticmethod
    def get_config(db: Session, config_key: str) -> Optional[Dict[str, Any]]:
        """获取配置"""
        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:
        """设置配置"""
        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]]:
        """获取服务的所有配置"""
        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
        ]

4.1.4 配置API接口

# backend/app/routes/config.py

router = APIRouter(prefix="/config", tags=["config"])

@router.get("/{config_key}")
async def get_config(
    config_key: str,
    db: Session = Depends(get_db),
    current_user: dict = Depends(get_current_active_user)
):
    """获取配置"""
    config = ConfigService.get_config(db, config_key)
    if not config:
        raise HTTPException(status_code=404, detail="配置不存在")
    return {"key": config_key, "value": config}

@router.post("/{config_key}")
async def set_config(
    config_key: str,
    config_data: Dict[str, Any],
    db: Session = Depends(get_db),
    current_user: dict = Depends(get_current_active_user)
):
    """设置配置"""
    success = ConfigService.set_config(
        db=db,
        config_key=config_key,
        config_value=config_data.get("value"),
        config_type=config_data.get("type", "system"),
        service_id=config_data.get("service_id"),
        description=config_data.get("description", "")
    )
    if not success:
        raise HTTPException(status_code=400, detail="设置配置失败")
    return {"message": "设置配置成功"}

@router.get("/service/{service_id}")
async def get_service_configs(
    service_id: str,
    db: Session = Depends(get_db),
    current_user: dict = Depends(get_current_active_user)
):
    """获取服务配置"""
    configs = ConfigService.get_service_configs(db, service_id)
    return {"service_id": service_id, "configs": configs}

4.1.5 前端配置界面

<!-- 前端配置管理组件 -->
<template>
  <div class="admin-config-container">
    <!-- 页面标题 -->
    <h1>配置管理</h1>
    
    <!-- 操作栏 -->
    <div class="action-bar">
      <el-button type="primary" @click="refreshConfigs">
        <el-icon><Refresh /></el-icon>
        刷新配置
      </el-button>
    </div>
    
    <!-- 系统配置 -->
    <el-card class="mb-4">
      <template #header>
        <div class="card-header">
          <span>系统配置</span>
        </div>
      </template>
      
      <el-form :model="systemConfigForm" label-width="120px">
        <el-form-item label="部署模式">
          <el-select v-model="systemConfigForm.deploymentMode" placeholder="选择部署模式">
            <el-option label="本地进程" value="local"></el-option>
            <el-option label="Docker" value="docker"></el-option>
            <el-option label="Supervisor" value="supervisor"></el-option>
          </el-select>
        </el-form-item>
        
        <el-form-item label="服务根目录">
          <el-input v-model="systemConfigForm.serviceRootDir" placeholder="服务根目录"></el-input>
        </el-form-item>
        
        <el-form-item>
          <el-button type="primary" @click="saveSystemConfig">保存配置</el-button>
        </el-form-item>
      </el-form>
    </el-card>
    
    <!-- 服务配置 -->
    <el-card>
      <template #header>
        <div class="card-header">
          <span>服务配置</span>
          <el-select v-model="selectedServiceId" placeholder="选择服务">
            <el-option 
              v-for="service in services" 
              :key="service.id" 
              :label="service.name" 
              :value="service.id"
            ></el-option>
          </el-select>
        </div>
      </template>
      
      <el-form v-if="selectedServiceId" :model="serviceConfigForm" label-width="120px">
        <el-form-item label="服务端口">
          <el-input-number v-model="serviceConfigForm.port" :min="1000" :max="65535"></el-input-number>
        </el-form-item>
        
        <el-form-item label="服务主机">
          <el-input v-model="serviceConfigForm.host" placeholder="服务主机"></el-input>
        </el-form-item>
        
        <el-form-item label="超时时间">
          <el-input-number v-model="serviceConfigForm.timeout" :min="1" :max="300"></el-input-number>
        </el-form-item>
        
        <el-form-item>
          <el-button type="primary" @click="saveServiceConfig">保存配置</el-button>
        </el-form-item>
      </el-form>
      <div v-else class="text-center text-gray-400 py-4">
        请选择一个服务
      </div>
    </el-card>
  </div>
</template>

<script setup lang="ts">
import { ref, onMounted } from 'vue'
import { Refresh } from '@element-plus/icons-vue'
import { ElMessage } from 'element-plus'
import axios from 'axios'

// 状态管理
const services = ref<any[]>([])
const selectedServiceId = ref('')

// 系统配置表单
const systemConfigForm = ref({
  deploymentMode: 'local',
  serviceRootDir: '/opt/ai-services'
})

// 服务配置表单
const serviceConfigForm = ref({
  port: 8001,
  host: '0.0.0.0',
  timeout: 30
})

// 加载服务列表
const loadServices = async () => {
  try {
    const token = localStorage.getItem('token')
    if (!token) {
      ElMessage.error('未登录,请重新登录')
      return
    }
    
    const response = await fetch('http://0.0.0.0:8001/api/v1/services', {
      method: 'GET',
      headers: {
        'Content-Type': 'application/json',
        'Authorization': `Bearer ${token}`
      }
    })
    
    if (!response.ok) {
      throw new Error('获取服务列表失败')
    }
    
    const data = await response.json()
    if (data.success) {
      services.value = data.services
    }
  } catch (error) {
    console.error('加载服务列表失败:', error)
    ElMessage.error('加载服务列表失败')
  }
}

// 加载系统配置
const loadSystemConfig = async () => {
  try {
    const token = localStorage.getItem('token')
    if (!token) {
      ElMessage.error('未登录,请重新登录')
      return
    }
    
    const response = await fetch('http://0.0.0.0:8001/api/v1/config/deployment.mode', {
      method: 'GET',
      headers: {
        'Content-Type': 'application/json',
        'Authorization': `Bearer ${token}`
      }
    })
    
    if (response.ok) {
      const data = await response.json()
      if (data.value) {
        systemConfigForm.value.deploymentMode = data.value
      }
    }
    
    const response2 = await fetch('http://0.0.0.0:8001/api/v1/config/service.root.dir', {
      method: 'GET',
      headers: {
        'Content-Type': 'application/json',
        'Authorization': `Bearer ${token}`
      }
    })
    
    if (response2.ok) {
      const data = await response2.json()
      if (data.value) {
        systemConfigForm.value.serviceRootDir = data.value
      }
    }
  } catch (error) {
    console.log('系统配置不存在,使用默认值')
  }
}

// 加载服务配置
const loadServiceConfig = async (serviceId: string) => {
  if (!serviceId) return
  
  try {
    const token = localStorage.getItem('token')
    if (!token) {
      ElMessage.error('未登录,请重新登录')
      return
    }
    
    const response = await fetch(`http://0.0.0.0:8001/api/v1/config/service/${serviceId}`, {
      method: 'GET',
      headers: {
        'Content-Type': 'application/json',
        'Authorization': `Bearer ${token}`
      }
    })
    
    if (response.ok) {
      const data = await response.json()
      if (data.configs) {
        const configs = data.configs
        configs.forEach((config: any) => {
          if (config.key === 'service.port') {
            serviceConfigForm.value.port = config.value
          } else if (config.key === 'service.host') {
            serviceConfigForm.value.host = config.value
          } else if (config.key === 'service.timeout') {
            serviceConfigForm.value.timeout = config.value
          }
        })
      }
    }
  } catch (error) {
    console.error('加载服务配置失败:', error)
    ElMessage.error('加载服务配置失败')
  }
}

// 保存系统配置
const saveSystemConfig = async () => {
  try {
    const token = localStorage.getItem('token')
    if (!token) {
      ElMessage.error('未登录,请重新登录')
      return
    }
    
    await fetch('http://0.0.0.0:8001/api/v1/config/deployment.mode', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'Authorization': `Bearer ${token}`
      },
      body: JSON.stringify({
        value: systemConfigForm.value.deploymentMode,
        type: 'system',
        description: '部署模式'
      })
    })
    
    await fetch('http://0.0.0.0:8001/api/v1/config/service.root.dir', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'Authorization': `Bearer ${token}`
      },
      body: JSON.stringify({
        value: systemConfigForm.value.serviceRootDir,
        type: 'system',
        description: '服务根目录'
      })
    })
    
    ElMessage.success('保存系统配置成功')
  } catch (error) {
    console.error('保存系统配置失败:', error)
    ElMessage.error('保存系统配置失败')
  }
}

// 保存服务配置
const saveServiceConfig = async () => {
  if (!selectedServiceId.value) return
  
  try {
    const token = localStorage.getItem('token')
    if (!token) {
      ElMessage.error('未登录,请重新登录')
      return
    }
    
    await fetch('http://0.0.0.0:8001/api/v1/config/service.port', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'Authorization': `Bearer ${token}`
      },
      body: JSON.stringify({
        value: serviceConfigForm.value.port,
        type: 'service',
        service_id: selectedServiceId.value,
        description: '服务端口'
      })
    })
    
    await fetch('http://0.0.0.0:8001/api/v1/config/service.host', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'Authorization': `Bearer ${token}`
      },
      body: JSON.stringify({
        value: serviceConfigForm.value.host,
        type: 'service',
        service_id: selectedServiceId.value,
        description: '服务主机'
      })
    })
    
    await fetch('http://0.0.0.0:8001/api/v1/config/service.timeout', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'Authorization': `Bearer ${token}`
      },
      body: JSON.stringify({
        value: serviceConfigForm.value.timeout,
        type: 'service',
        service_id: selectedServiceId.value,
        description: '服务超时时间'
      })
    })
    
    ElMessage.success('保存服务配置成功')
  } catch (error) {
    console.error('保存服务配置失败:', error)
    ElMessage.error('保存服务配置失败')
  }
}

// 刷新配置
const refreshConfigs = async () => {
  await loadSystemConfig()
  if (selectedServiceId.value) {
    await loadServiceConfig(selectedServiceId.value)
  }
  ElMessage.success('配置已刷新')
}

// 监听服务选择变化
const handleServiceChange = () => {
  loadServiceConfig(selectedServiceId.value)
}

// 初始化
onMounted(() => {
  loadServices()
  loadSystemConfig()
})
</script>

<style scoped>
.admin-config-container {
  padding: 20px;
}

.card-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
}

.mb-4 {
  margin-bottom: 20px;
}
</style>

4.2 第二步:多服务目录标准化

4.2.1 统一服务根目录

/opt/ai-services/  # 所有AI服务的根目录
├── config/        # 全局配置
│   ├── common.py  # 公共配置
│   └── ports.py   # 端口分配配置
├── logs/          # 所有服务的日志总目录
│   ├── service-1.log
│   ├── service-2.log
│   └── service-3.log
├── service-1/     # 服务1如文本分类
│   ├── ai_algorithm.py  # 服务1的AI算法逻辑
│   ├── main.py          # 服务1的FastAPI接口
│   ├── requirements.txt # 服务1的依赖
│   ├── config.py        # 服务1的独立配置
│   └── venv/            # 服务1的虚拟环境
├── service-2/     # 服务2如图像识别
│   ├── ai_algorithm.py
│   ├── main.py
│   ├── requirements.txt
│   ├── config.py
│   └── venv/
└── service-3/     # 服务3如语音转文字
    ├── ...

4.2.2 统一接口规范

所有服务必须实现以下接口:

  • POST /predict:算法预测接口
  • GET /health:健康检查接口
  • GET /info:服务信息接口

4.2.3 统一启动方式

所有服务使用统一的启动脚本:

# /opt/ai-services/service-1/start.sh
#!/bin/bash
cd /opt/ai-services/service-1
source venv/bin/activate
python main.py

4.3 第三步:使用 Supervisor 统一管理服务

4.3.1 安装 Supervisor

# Ubuntu/Debian
apt update && apt install supervisor

# CentOS/RHEL
yum install epel-release
yum install supervisor

# 启动 Supervisor 服务
systemctl start supervisor
systemctl enable supervisor

4.3.2 配置 Supervisor

创建统一的配置文件:

# /etc/supervisor/conf.d/ai-services.conf

[supervisord]
logfile=/opt/ai-services/logs/supervisord.log
logfile_maxbytes=50MB
logfile_backups=10
loglevel=info
pidfile=/var/run/supervisord.pid
nodaemon=false
minfds=1024
minprocs=200

# 服务1文本分类8001端口
[program:ai-service-1]
name=ai-service-1
command=/opt/ai-services/service-1/start.sh
directory=/opt/ai-services/service-1
user=ubuntu
autostart=true
autorestart=true
startretries=3
stdout_logfile=/opt/ai-services/logs/service-1.log
stderr_logfile=/opt/ai-services/logs/service-1_error.log
stdout_logfile_maxbytes=10MB
stdout_logfile_backups=5

# 服务2图像识别8002端口
[program:ai-service-2]
name=ai-service-2
command=/opt/ai-services/service-2/start.sh
directory=/opt/ai-services/service-2
user=ubuntu
autostart=true
autorestart=true
startretries=3
stdout_logfile=/opt/ai-services/logs/service-2.log
stderr_logfile=/opt/ai-services/logs/service-2_error.log
stdout_logfile_maxbytes=10MB
stdout_logfile_backups=5

# 服务3语音转文字8003端口
[program:ai-service-3]
name=ai-service-3
command=/opt/ai-services/service-3/start.sh
directory=/opt/ai-services/service-3
user=ubuntu
autostart=true
autorestart=true
startretries=3
stdout_logfile=/opt/ai-services/logs/service-3.log
stderr_logfile=/opt/ai-services/logs/service-3_error.log
stdout_logfile_maxbytes=10MB
stdout_logfile_backups=5

4.3.3 Supervisor 管理命令

# 重新加载配置(新增/修改服务后执行)
supervisorctl reload

# 启动所有AI服务
supervisorctl start ai-service-*

# 启动单个服务
supervisorctl start ai-service-1

# 查看所有服务状态
supervisorctl status
# 输出示例:
# ai-service-1                    RUNNING   pid 1234, uptime 0:05:10
# ai-service-2                    RUNNING   pid 1235, uptime 0:05:08
# ai-service-3                    RUNNING   pid 1236, uptime 0:05:05

# 重启所有服务
supervisorctl restart ai-service-*

# 停止单个服务
supervisorctl stop ai-service-2

# 查看某个服务的日志(快速排查问题)
supervisorctl tail -f ai-service-1

4.4 第四步:配置集中化管理

4.4.1 配置管理架构

采用三层配置管理架构:

  1. 数据库配置:存储在数据库中的动态配置,支持界面修改
  2. 文件配置:存储在文件中的静态配置,作为默认值
  3. 环境变量:优先级最高,用于覆盖其他配置

4.4.2 配置加载流程

# backend/app/config/settings.py

from pydantic_settings import BaseSettings
from typing import Optional, Dict, Any
from sqlalchemy.orm import Session
from app.models.database import SessionLocal
from app.models.models import ServiceConfig

class Settings(BaseSettings):
    """应用配置类"""
    # 应用基本配置
    APP_NAME: str = "智能算法展示平台"
    APP_VERSION: str = "1.0.0"
    DEBUG: bool = True
    
    # 数据库配置
    DATABASE_URL: str = "postgresql://admin:password@localhost:5432/algorithm_db"
    
    # 其他配置...
    
    # 服务管理配置
    SERVICE_MANAGEMENT: Dict[str, Any] = {
        "mode": "supervisor",  # 服务管理模式local, docker, supervisor
        "service_root_dir": "/opt/ai-services",
        "supervisor_config_dir": "/etc/supervisor/conf.d",
    }
    
    class Config:
        env_file = ".env"
        case_sensitive = True
        extra = "allow"  # 允许额外的环境变量

    def get_config(self, config_key: str, default: Any = None) -> Any:
        """获取配置,优先级:环境变量 > 数据库 > 文件默认值"""
        # 1. 先从环境变量获取
        env_value = getattr(self, config_key.upper().replace('.', '_'), None)
        if env_value is not None:
            return env_value
        
        # 2. 从数据库获取
        db: Session = SessionLocal()
        try:
            config = db.query(ServiceConfig).filter_by(
                config_key=config_key,
                status="active"
            ).first()
            if config:
                return config.config_value
        finally:
            db.close()
        
        # 3. 返回默认值
        return default


# 创建全局配置实例
settings = Settings()

4.4.3 配置服务集成

# backend/app/services/service_orchestrator.py

class ServiceOrchestrator:
    """服务编排服务"""
    
    def __init__(self, deployment_mode="local"):
        """初始化服务编排器
        
        Args:
            deployment_mode: 部署模式,支持"docker"、"local"和"supervisor"
        """
        # 从数据库获取配置
        self.deployment_mode = settings.get_config("deployment.mode", deployment_mode)
        self.service_root_dir = settings.get_config("service.root.dir", "/opt/ai-services")
        # 其他初始化代码...
    
    def _get_service_config(self, service_id: str) -> Dict[str, Any]:
        """获取服务配置"""
        # 基础配置
        base_config = {
            "host": "0.0.0.0",
            "port": self._get_service_port(service_id),
            "timeout": 30,
            "health_check_interval": 10,
        }
        
        # 从数据库获取服务特定配置
        db: Session = SessionLocal()
        try:
            configs = db.query(ServiceConfig).filter_by(
                service_id=service_id,
                status="active"
            ).all()
            
            for config in configs:
                # 解析配置键,设置到相应的位置
                if config.config_key == "service.port":
                    base_config["port"] = config.config_value
                elif config.config_key == "service.host":
                    base_config["host"] = config.config_value
                elif config.config_key == "service.timeout":
                    base_config["timeout"] = config.config_value
        finally:
            db.close()
        
        return base_config

4.4.4 配置管理最佳实践

  1. 配置分类

    • system:系统级配置,影响所有服务
    • service:服务级配置,仅影响特定服务
    • user:用户级配置,与用户偏好相关
  2. 配置命名规范

    • 使用点分隔的命名方式:category.subcategory.setting
    • 示例:service.port, deployment.mode, logging.level
  3. 配置版本管理

    • 保留配置的历史版本
    • 支持配置回滚
    • 记录配置修改日志
  4. 配置验证

    • 对配置值进行类型检查
    • 对配置值进行范围验证
    • 确保配置的完整性
  5. 配置安全

    • 敏感配置加密存储
    • 配置访问权限控制
    • 配置变更审计

4.5 第五步:可选优化 - 统一 API 网关

4.5.1 安装 Nginx

# Ubuntu/Debian
apt update && apt install nginx

# CentOS/RHEL
yum install nginx

# 启动 Nginx 服务
systemctl start nginx
systemctl enable nginx

4.5.2 配置 Nginx 反向代理

# /etc/nginx/conf.d/ai-services.conf
server {
    listen 80;
    server_name your-server-ip;  # 替换为你的服务器IP/域名

    # 服务1文本分类网关路径/ai/text-classify
    location /ai/text-classify/ {
        proxy_pass http://127.0.0.1:8001/;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_connect_timeout 30s;
        proxy_read_timeout 30s;
    }

    # 服务2图像识别网关路径/ai/image-recog
    location /ai/image-recog/ {
        proxy_pass http://127.0.0.1:8002/;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_connect_timeout 30s;
        proxy_read_timeout 30s;
    }

    # 服务3语音转文字网关路径/ai/speech-to-text
    location /ai/speech-to-text/ {
        proxy_pass http://127.0.0.1:8003/;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_connect_timeout 30s;
        proxy_read_timeout 30s;
    }
}

4.5.3 重启 Nginx 并测试

# 检查配置是否正确
nginx -t

# 重启Nginx
systemctl restart nginx

# 测试网关调用(无需记端口,只需记路径)
curl -X POST "http://your-server-ip/ai/text-classify/predict" \
-H "Content-Type: application/json" \
-d '{"input_data": ["这是一个测试文本"], "batch_id": "test_001"}'

5. 与现有系统集成

5.1 集成 ServiceOrchestrator

修改现有的 ServiceOrchestrator 类,使其支持 Supervisor 管理模式和数据库配置:

# backend/app/services/service_orchestrator.py

class ServiceOrchestrator:
    """服务编排服务"""
    
    def __init__(self, deployment_mode="local"):
        """初始化服务编排器
        
        Args:
            deployment_mode: 部署模式,支持"docker"、"local"和"supervisor"
        """
        # 从数据库获取配置
        self.deployment_mode = settings.get_config("deployment.mode", deployment_mode)
        self.service_root_dir = settings.get_config("service.root.dir", "/opt/ai-services")
        # 其他初始化代码...
    
    def deploy_service(self, service_id: str, service_config: Dict[str, Any], project_info: Dict[str, Any]) -> Dict[str, Any]:
        """部署服务"""
        try:
            if self.deployment_mode == "supervisor":
                # 使用 Supervisor 部署服务
                return self._deploy_with_supervisor(service_id, service_config, project_info)
            # 其他部署模式...
        except Exception as e:
            # 错误处理...
    
    def _deploy_with_supervisor(self, service_id: str, service_config: Dict[str, Any], project_info: Dict[str, Any]) -> Dict[str, Any]:
        """使用 Supervisor 部署服务"""
        # 1. 创建服务目录
        service_dir = self._create_service_directory(service_id)
        
        # 2. 生成服务配置和启动脚本
        self._generate_service_config(service_dir, service_id, service_config)
        self._generate_start_script(service_dir, service_id)
        
        # 3. 创建 Supervisor 配置
        self._create_supervisor_config(service_id, service_dir, service_config)
        
        # 4. 重新加载 Supervisor 配置
        self._reload_supervisor()
        
        # 5. 启动服务
        self._start_supervisor_service(service_id)
        
        # 6. 验证服务启动
        if not self._verify_service_startup(service_id, service_config):
            return {
                "success": False,
                "error": "服务启动验证失败",
                "service_id": service_id,
                "status": "error",
                "api_url": None
            }
        
        # 7. 构建 API URL
        api_url = f"http://{service_config.get('host', 'localhost')}:{service_config.get('port', 8000)}"
        
        # 8. 保存服务配置到数据库
        self._save_service_config_to_db(service_id, service_config)
        
        return {
            "success": True,
            "service_id": service_id,
            "status": "running",
            "api_url": api_url,
            "error": None
        }
    
    def _save_service_config_to_db(self, service_id: str, service_config: Dict[str, Any]):
        """保存服务配置到数据库"""
        db = SessionLocal()
        try:
            # 保存服务端口
            ConfigService.set_config(
                db=db,
                config_key="service.port",
                config_value=service_config.get("port"),
                config_type="service",
                service_id=service_id,
                description="服务端口"
            )
            
            # 保存服务主机
            ConfigService.set_config(
                db=db,
                config_key="service.host",
                config_value=service_config.get("host", "0.0.0.0"),
                config_type="service",
                service_id=service_id,
                description="服务主机"
            )
            
            # 保存服务超时
            ConfigService.set_config(
                db=db,
                config_key="service.timeout",
                config_value=service_config.get("timeout", 30),
                config_type="service",
                service_id=service_id,
                description="服务超时时间"
            )
        finally:
            db.close()
    
    # 其他方法...

5.2 集成配置管理

修改现有配置管理,使用数据库存储配置:

# backend/app/config/settings.py

from pydantic_settings import BaseSettings
from typing import Optional, Dict, Any
from sqlalchemy.orm import Session
from app.models.database import SessionLocal
from app.models.models import ServiceConfig


class Settings(BaseSettings):
    """应用配置类"""
    # 应用基本配置
    APP_NAME: str = "智能算法展示平台"
    APP_VERSION: str = "1.0.0"
    DEBUG: bool = True
    
    # 数据库配置
    DATABASE_URL: str = "postgresql://admin:password@localhost:5432/algorithm_db"
    
    # 其他配置...
    
    # 服务管理配置
    SERVICE_MANAGEMENT: Dict[str, Any] = {
        "mode": "supervisor",  # 服务管理模式local, docker, supervisor
        "service_root_dir": "/opt/ai-services",
        "supervisor_config_dir": "/etc/supervisor/conf.d",
    }
    
    class Config:
        env_file = ".env"
        case_sensitive = True
        extra = "allow"  # 允许额外的环境变量

    def get_config(self, config_key: str, default: Any = None) -> Any:
        """获取配置,优先级:环境变量 > 数据库 > 文件默认值"""
        # 1. 先从环境变量获取
        env_value = getattr(self, config_key.upper().replace('.', '_'), None)
        if env_value is not None:
            return env_value
        
        # 2. 从数据库获取
        db: Session = SessionLocal()
        try:
            config = db.query(ServiceConfig).filter_by(
                config_key=config_key,
                status="active"
            ).first()
            if config:
                return config.config_value
        finally:
            db.close()
        
        # 3. 返回默认值
        return default


# 创建全局配置实例
settings = Settings()

5.3 集成服务状态查询

修改服务状态查询接口,支持 Supervisor 管理的服务:

# backend/app/routes/services.py

@router.get("/status/{service_id}")
async def get_service_status(
    service_id: str,
    orchestrator: ServiceOrchestrator = Depends(get_orchestrator)
):
    """获取服务状态"""
    try:
        # 获取服务状态
        status_info = orchestrator.get_service_status(service_id)
        
        if not status_info["success"]:
            raise HTTPException(status_code=404, detail=status_info.get("error", "服务不存在"))
        
        return {
            "service_id": service_id,
            "status": status_info["status"],
            "health": status_info["health"],
            "message": "获取服务状态成功"
        }
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))

5.4 集成配置 API

添加配置管理 API 接口:

# backend/app/routes/config.py

from fastapi import APIRouter, Depends, HTTPException
from sqlalchemy.orm import Session
from typing import Dict, Any, List, Optional

from app.models.database import get_db
from app.services.config_service import ConfigService
from app.services.user import get_current_active_user

router = APIRouter(prefix="/config", tags=["config"])

@router.get("/{config_key}")
async def get_config(
    config_key: str,
    db: Session = Depends(get_db),
    current_user: dict = Depends(get_current_active_user)
):
    """获取配置"""
    config = ConfigService.get_config(db, config_key)
    if not config:
        raise HTTPException(status_code=404, detail="配置不存在")
    return {"key": config_key, "value": config}

@router.post("/{config_key}")
async def set_config(
    config_key: str,
    config_data: Dict[str, Any],
    db: Session = Depends(get_db),
    current_user: dict = Depends(get_current_active_user)
):
    """设置配置"""
    success = ConfigService.set_config(
        db=db,
        config_key=config_key,
        config_value=config_data.get("value"),
        config_type=config_data.get("type", "system"),
        service_id=config_data.get("service_id"),
        description=config_data.get("description", "")
    )
    if not success:
        raise HTTPException(status_code=400, detail="设置配置失败")
    return {"message": "设置配置成功"}

@router.get("/service/{service_id}")
async def get_service_configs(
    service_id: str,
    db: Session = Depends(get_db),
    current_user: dict = Depends(get_current_active_user)
):
    """获取服务配置"""
    configs = ConfigService.get_service_configs(db, service_id)
    return {"service_id": service_id, "configs": configs}

6. Gitea 集成方案

6.1 Gitea 集成概述

针对所有工程都在 Gitea 上的场景,本方案提供了完整的 Gitea 集成能力,实现从代码仓库到服务部署的全流程管理。基于现有的 GiteaService 和 GiteaClient 实现,进一步完善了从代码管理到服务部署的自动化流程。

6.2 现有 Gitea 集成实现

当前系统已经实现了完整的 Gitea 集成功能:

  • Gitea 连接配置管理
  • 仓库创建、克隆、推送、拉取
  • 代码上传(支持大文件处理)
  • 从 Gitea 部署服务
  • 错误处理和重试机制
  • CI/CD 集成支持

6.3 Gitea 配置管理gitea_configs

6.3.1 配置存储架构

系统使用 gitea_configs 表存储 Gitea 连接配置,实现了配置的持久化和版本管理:

# backend/app/models/models.py

class GiteaConfig(Base):
    """Gitea配置模型"""
    __tablename__ = "gitea_configs"
    
    id = Column(String, primary_key=True, index=True)
    server_url = Column(String, nullable=False)  # Gitea服务器URL
    access_token = Column(String, nullable=False)  # 访问令牌
    default_owner = Column(String, nullable=False)  # 默认组织/用户
    repo_prefix = Column(String, default="")  # 仓库前缀
    status = Column(String, default="active")  # 状态
    created_at = Column(DateTime(timezone=True), server_default=func.now())
    updated_at = Column(DateTime(timezone=True), onupdate=func.now())

6.3.2 配置管理实现

Gitea 配置管理通过 GiteaService 实现,支持配置的加载、保存和使用:

# backend/app/gitea/service.py

class GiteaService:
    def _load_config(self) -> Optional[Dict[str, Any]]:
        """加载Gitea配置"""
        try:
            db = SessionLocal()
            # 从数据库中获取配置(只取第一个配置)
            config = db.query(GiteaConfig).filter_by(status="active").first()
            db.close()
            
            if config:
                return {
                    'id': config.id,
                    'server_url': config.server_url,
                    'access_token': config.access_token,
                    'default_owner': config.default_owner,
                    'repo_prefix': config.repo_prefix,
                    'status': config.status
                }
            
            # 配置不存在时返回默认值
            return {
                'server_url': getattr(settings, 'GITEA_SERVER_URL', ''),
                'access_token': getattr(settings, 'GITEA_ACCESS_TOKEN', ''),
                'default_owner': getattr(settings, 'GITEA_DEFAULT_OWNER', ''),
                'repo_prefix': getattr(settings, 'GITEA_REPO_PREFIX', '')
            }
        except Exception as e:
            logger.error(f"Failed to load Gitea config from database: {str(e)}")
            # 出错时返回默认配置
            return {
                'server_url': getattr(settings, 'GITEA_SERVER_URL', ''),
                'access_token': getattr(settings, 'GITEA_ACCESS_TOKEN', ''),
                'default_owner': getattr(settings, 'GITEA_DEFAULT_OWNER', ''),
                'repo_prefix': getattr(settings, 'GITEA_REPO_PREFIX', '')
            }
    
    def save_config(self, config: Dict[str, Any]) -> bool:
        """保存Gitea配置"""
        try:
            db = SessionLocal()
            
            # 将所有现有配置设置为非活动状态
            db.query(GiteaConfig).update({GiteaConfig.status: "inactive"})
            
            # 检查是否已有配置
            existing_config = db.query(GiteaConfig).first()
            
            if existing_config:
                # 更新现有配置
                existing_config.server_url = config['server_url']
                existing_config.access_token = config['access_token']
                existing_config.default_owner = config['default_owner']
                existing_config.repo_prefix = config.get('repo_prefix', '')
                existing_config.status = "active"
            else:
                # 创建新配置
                new_config = GiteaConfig(
                    id=f"gitea-config-{uuid.uuid4()}",
                    server_url=config['server_url'],
                    access_token=config['access_token'],
                    default_owner=config['default_owner'],
                    repo_prefix=config.get('repo_prefix', ''),
                    status="active"
                )
                db.add(new_config)
            
            db.commit()
            db.close()
            
            # 更新内存中的配置
            self.config = config
            self.client = GiteaClient(
                config['server_url'],
                config['access_token']
            )
            
            logger.info("Gitea config saved to database successfully")
            return True
        except Exception as e:
            logger.error(f"Failed to save Gitea config to database: {str(e)}")
            return False

6.3.3 配置使用流程

  1. 配置加载:系统启动时,GiteaService 会从数据库加载 Gitea 配置
  2. 配置验证:使用加载的配置初始化 GiteaClient,测试连接
  3. 配置使用:在仓库操作、代码上传等功能中使用配置
  4. 配置更新:通过 API 或界面更新配置,自动保存到数据库

6.3.4 配置管理最佳实践

  1. 配置版本控制:系统会将旧配置标记为 inactive,保留配置历史
  2. 配置验证:保存配置前应测试连接,确保配置有效
  3. 安全存储:访问令牌应妥善保管,避免泄露
  4. 配置备份:定期备份 gitea_configs 表,防止配置丢失

6.3.5 配置 API 接口

系统提供了 Gitea 配置管理的 API 接口:

  • GET /api/v1/gitea/config:获取当前 Gitea 配置
  • POST /api/v1/gitea/config:更新 Gitea 配置
  • GET /api/v1/gitea/test-connection:测试 Gitea 连接状态

6.4 核心功能

  • 配置管理:获取、设置 Gitea 连接配置,支持环境变量和数据库存储
  • 连接测试:测试与 Gitea 服务器的连接状态
  • 仓库管理:创建、克隆、推送、拉取 Gitea 仓库
  • 代码上传:支持大量文件上传,解决 HTTP 413 错误
  • 大文件处理:支持大文件分阶段推送,优化推送性能
  • 服务部署:从 Gitea 仓库直接部署算法服务
  • 算法注册:从仓库注册算法服务到系统

6.5 集成架构

┌─────────────────────────────────────────────────────────┐
│                    管理层                              │
│  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐     │
│  │ Supervisor  │  │   Nginx     │  │ Gitea服务  │     │
│  └─────────────┘  └─────────────┘  └─────────────┘     │
├─────────────────────────────────────────────────────────┤
│                    服务层                              │
│  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐     │
│  │ Service-1   │  │ Service-2   │  │ Service-3   │     │
│  │ 端口: 8001  │  │ 端口: 8002  │  │ 端口: 8003  │     │
│  └─────────────┘  └─────────────┘  └─────────────┘     │
├─────────────────────────────────────────────────────────┤
│                    代码层                              │
│  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐     │
│  │ Gitea仓库1  │  │ Gitea仓库2  │  │ Gitea仓库3  │     │
│  └─────────────┘  └─────────────┘  └─────────────┘     │
├─────────────────────────────────────────────────────────┤
│                    基础设施层                           │
│  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐     │
│  │ 操作系统    │  │ 网络        │  │ 文件系统    │     │
│  └─────────────┘  └─────────────┘  └─────────────┘     │
└─────────────────────────────────────────────────────────┘

6.6 从 Gitea 部署服务的完整流程

6.6.1 配置 Gitea 连接

  1. 设置 Gitea 配置

    • 服务器 URL
    • 访问令牌
    • 默认所有者
    • 仓库前缀
  2. 测试连接

    # 使用现有的 GiteaService 测试连接
    python -c "from app.gitea.service import gitea_service; print(gitea_service.test_connection())"
    
  3. API 接口

    # 获取 Gitea 配置
    curl -X GET "http://localhost:8001/api/v1/gitea/config" -H "Authorization: Bearer <token>"
    
    # 设置 Gitea 配置
    curl -X POST "http://localhost:8001/api/v1/gitea/config" -H "Authorization: Bearer <token>" -H "Content-Type: application/json" -d '{
      "server_url": "https://gitea.example.com",
      "access_token": "your-token",
      "default_owner": "owner",
      "repo_prefix": "AI-"
    }'
    

6.6.2 仓库管理流程

  1. 创建仓库

    from app.gitea.service import gitea_service
    
    repo = gitea_service.create_repository(
        algorithm_id="text-classification",
        algorithm_name="文本分类算法",
        description="基于 BERT 的文本分类算法"
    )
    print(repo)
    
  2. 克隆仓库

    success = gitea_service.clone_repository(
        repo_url="https://gitea.example.com/owner/text-classification.git",
        algorithm_id="text-classification"
    )
    print(f"Clone success: {success}")
    
  3. 推送代码

    success = gitea_service.push_to_repository(
        algorithm_id="text-classification",
        message="Update algorithm code"
    )
    print(f"Push success: {success}")
    
  4. 上传文件

    # 使用 API 上传文件
    curl -X POST "http://localhost:8001/api/v1/gitea/repos/upload" -H "Authorization: Bearer <token>" -F "algorithm_id=text-classification" -F "files=@algorithm.py" -F "files=@model.pth"
    

6.6.3 从 Gitea 部署服务

  1. 通过 API 部署

    # 从 Gitea 部署服务
    curl -X POST "http://localhost:8001/api/v1/services/deploy-from-gitea" -H "Authorization: Bearer <token>" -H "Content-Type: application/json" -d '{
      "algorithm_id": "text-classification",
      "repo_url": "https://gitea.example.com/owner/text-classification.git",
      "branch": "main",
      "service_config": {
        "name": "文本分类服务",
        "port": 8001,
        "host": "0.0.0.0",
        "timeout": 30
      }
    }'
    
  2. 通过前端界面部署

    • 登录前端管理界面
    • 进入「服务管理」页面
    • 点击「从 Gitea 部署」按钮
    • 填写部署信息并提交

6.6.4 服务管理和监控

  1. 服务状态查询

    curl -X GET "http://localhost:8001/api/v1/services/status/text-classification" -H "Authorization: Bearer <token>"
    
  2. 服务日志查询

    curl -X GET "http://localhost:8001/api/v1/services/logs/text-classification?lines=100" -H "Authorization: Bearer <token>"
    
  3. 服务操作

    # 启动服务
    curl -X POST "http://localhost:8001/api/v1/services/start/text-classification" -H "Authorization: Bearer <token>"
    
    # 停止服务
    curl -X POST "http://localhost:8001/api/v1/services/stop/text-classification" -H "Authorization: Bearer <token>"
    
    # 重启服务
    curl -X POST "http://localhost:8001/api/v1/services/restart/text-classification" -H "Authorization: Bearer <token>"
    

7. 数据库设计与实现

7.1 数据库架构

系统使用 PostgreSQL 数据库,包含以下核心表:

  1. algorithms:算法信息表,存储算法的基本信息
  2. algorithm_versions:算法版本表,存储算法的不同版本
  3. roles:角色表,存储用户角色信息
  4. users:用户表,存储用户信息
  5. algorithm_calls:算法调用记录表,存储算法调用的历史记录
  6. gitea_configsGitea配置表存储Gitea连接配置
  7. algorithm_repositories:算法仓库表,存储算法代码仓库信息
  8. service_groups:服务分组表,存储服务分组信息
  9. algorithm_services:算法服务表,存储算法服务的部署信息
  10. service_configs:服务配置表,存储服务的配置信息

7.2 数据关系

┌─────────────────┐      ┌─────────────────────┐
│   algorithms    │┼──────│algorithm_versions  │
└─────────────────┘      └─────────────────────┘
        │                      │
        │                      │
        │                      │
┌─────────────────┐      ┌─────────────────────┐
│algorithm_calls  │┼──────│   users            │
└─────────────────┘      └─────────────────────┘
                              │
                              │
┌─────────────────┐      ┌─────────────────────┐
│  gitea_configs  │      │      roles         │
└─────────────────┘      └─────────────────────┘
        │
        │
┌─────────────────┐      ┌─────────────────────┐
│algorithm_repos  │┼──────│algorithm_services  │
└─────────────────┘      └─────────────────────┘
                              │
                              │
┌─────────────────┐      ┌─────────────────────┐
│service_groups   │      │  service_configs   │
└─────────────────┘      └─────────────────────┘

7.3 数据库初始化

# backend/init_db.py

from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from app.models.database import Base
from app.models.models import Algorithm, AlgorithmVersion, Role, User, AlgorithmCall, GiteaConfig, AlgorithmRepository, ServiceGroup, AlgorithmService, ServiceConfig

# 创建数据库引擎
engine = create_engine("postgresql://admin:password@localhost:5432/algorithm_db")

# 创建所有表
Base.metadata.create_all(bind=engine)

# 创建会话
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
db = SessionLocal()

# 初始化默认角色
try:
    # 检查是否已存在角色
    admin_role = db.query(Role).filter_by(name="admin").first()
    if not admin_role:
        admin_role = Role(
            id="role-admin",
            name="admin",
            description="管理员角色,拥有所有权限"
        )
        db.add(admin_role)
    
    user_role = db.query(Role).filter_by(name="user").first()
    if not user_role:
        user_role = Role(
            id="role-user",
            name="user",
            description="普通用户角色,拥有基本权限"
        )
        db.add(user_role)
    
    db.commit()
    print("默认角色初始化成功")
except Exception as e:
    db.rollback()
    print(f"初始化默认角色失败: {str(e)}")

# 关闭会话
db.close()

## 8. 总结与最佳实践

### 8.1 方案总结

本方案提供了一个完整的多独立 AI 算法服务管理解决方案解决了端口冲突统一管理配置管理运维效率和服务独立性等核心诉求通过以下关键技术实现

1. **服务标准化**统一目录结构接口规范和启动方式提高服务的一致性和可维护性
2. **Supervisor 统一管理**批量管理所有服务的启停监控和自动重启减少人工干预
3. **配置集中化**采用数据库存储配置支持界面修改实现配置的动态管理
4. **Gitea 集成**实现从代码管理到服务部署的全流程自动化提高开发和部署效率
5. **数据库配置管理**支持在界面上配置并存储到数据库中实现配置的版本管理和历史追踪

### 8.2 最佳实践

1. **服务设计**
   - 每个服务应保持独立避免与其他服务产生强依赖
   - 实现标准化的健康检查和服务信息接口
   - 合理设置服务的超时时间和资源限制

2. **配置管理**
   - 使用分层配置管理环境变量 > 数据库配置 > 文件配置
   - 为配置设置合理的命名规范便于管理和维护
   - 定期备份配置数据防止配置丢失

3. **部署管理**
   - 使用 Supervisor 管理服务确保服务的可靠运行
   - 实现服务的自动重启机制提高服务的可用性
   - 为每个服务分配唯一的端口避免端口冲突

4. **监控与运维**
   - 实现服务的健康检查和状态监控
   - 集中管理服务日志便于问题排查
   - 建立服务的告警机制及时发现和处理服务异常

5. **安全管理**
   - 保护敏感配置信息避免泄露
   - 实现服务的访问控制确保服务的安全性
   - 定期更新服务依赖修复安全漏洞

### 8.3 后续优化方向

1. **服务发现与注册**实现服务的自动发现和注册机制减少手动配置
2. **负载均衡**为高流量服务添加负载均衡机制提高服务的并发处理能力
3. **容器化部署**结合 Docker 容器化技术提高服务的可移植性和一致性
4. **CI/CD 集成**实现代码提交到服务部署的自动化流程提高开发效率
5. **监控系统**集成 Prometheus + Grafana 等监控系统提供更全面的服务监控

### 8.4 实施建议

1. **分阶段实施**先在测试环境验证方案的可行性再逐步推广到生产环境
2. **培训与文档**为运维人员提供详细的培训和文档确保方案的正确实施
3. **持续优化**根据实际运行情况持续优化服务管理方案
4. **风险评估**在实施前进行充分的风险评估制定应对措施

通过本方案的实施您可以构建一个高效可靠易管理的多独立 AI 算法服务管理系统为算法的开发部署和运行提供有力的支持