"""
============================================================================
算子开发效率平台 - 后端服务
============================================================================
提供以下功能:
1. 环境部署 - 连接远程服务器、下载脚本、执行脚本、返回日志
2. 学习共享 - 管理学习分类和内容
3. 材料查询 - 管理查询分类和内容
4. 模块管理 - 管理平台功能模块
使用 Flask 框架,支持 RESTful API
"""
import os
import json
import time
import uuid
import threading
import logging
from datetime import datetime
from typing import Dict, List, Optional, Any
from dataclasses import dataclass, asdict
from flask import Flask, request, jsonify, Response, stream_with_context
from flask_cors import CORS
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)
logger = logging.getLogger(__name__)
app = Flask(__name__)
CORS(app)
DATA_DIR = os.path.join(os.path.dirname(__file__), 'data')
os.makedirs(DATA_DIR, exist_ok=True)
@dataclass
class Module:
"""功能模块"""
id: int
name: str
icon: str
desc: str
url: str
enabled: bool = True
@dataclass
class LearningItem:
"""学习内容"""
id: int
title: str
desc: str
wiki_url: str
@dataclass
class LearningCategory:
"""学习分类"""
id: int
name: str
icon: str
items: List[LearningItem]
@dataclass
class QueryItem:
"""查询内容"""
id: int
title: str
desc: str
wiki_url: str
@dataclass
class QueryCategory:
"""查询分类"""
id: int
name: str
icon: str
items: List[QueryItem]
@dataclass
class DeploymentRecord:
"""部署记录"""
id: str
server: str
port: int
username: str
version: str
components: str
success: bool
time: str
logs: List[Dict[str, str]]
@dataclass
class DeploymentTask:
"""部署任务"""
id: str
status: str
config: Dict[str, Any]
logs: List[Dict[str, str]]
start_time: Optional[str] = None
end_time: Optional[str] = None
class DataManager:
"""数据管理器"""
def __init__(self):
self.modules_file = os.path.join(DATA_DIR, 'modules.json')
self.learning_file = os.path.join(DATA_DIR, 'learning.json')
self.query_file = os.path.join(DATA_DIR, 'query.json')
self.deployment_file = os.path.join(DATA_DIR, 'deployment.json')
self.tasks: Dict[str, DeploymentTask] = {}
def _load_json(self, filepath: str, default: Any = None) -> Any:
"""加载 JSON 文件"""
if default is None:
default = []
if not os.path.exists(filepath):
return default
try:
with open(filepath, 'r', encoding='utf-8') as f:
return json.load(f)
except Exception as e:
logger.error(f"Failed to load {filepath}: {e}")
return default
def _save_json(self, filepath: str, data: Any) -> bool:
"""保存 JSON 文件"""
try:
with open(filepath, 'w', encoding='utf-8') as f:
json.dump(data, f, ensure_ascii=False, indent=2)
return True
except Exception as e:
logger.error(f"Failed to save {filepath}: {e}")
return False
def get_modules(self) -> List[Dict]:
"""获取所有模块"""
return self._load_json(self.modules_file)
def save_module(self, module: Dict) -> bool:
"""保存模块"""
modules = self.get_modules()
modules.append(module)
return self._save_json(self.modules_file, modules)
def update_module(self, module_id: int, data: Dict) -> bool:
"""更新模块"""
modules = self.get_modules()
for i, m in enumerate(modules):
if m['id'] == module_id:
modules[i] = {**m, **data}
return self._save_json(self.modules_file, modules)
return False
def delete_module(self, module_id: int) -> bool:
"""删除模块"""
modules = self.get_modules()
modules = [m for m in modules if m['id'] != module_id]
return self._save_json(self.modules_file, modules)
def get_learning_categories(self) -> List[Dict]:
"""获取学习分类"""
return self._load_json(self.learning_file)
def save_learning_category(self, category: Dict) -> bool:
"""保存学习分类"""
categories = self.get_learning_categories()
categories.append(category)
return self._save_json(self.learning_file, categories)
def update_learning_category(self, category_id: int, data: Dict) -> bool:
"""更新学习分类"""
categories = self.get_learning_categories()
for i, c in enumerate(categories):
if c['id'] == category_id:
categories[i] = {**c, **data}
return self._save_json(self.learning_file, categories)
return False
def delete_learning_category(self, category_id: int) -> bool:
"""删除学习分类"""
categories = self.get_learning_categories()
categories = [c for c in categories if c['id'] != category_id]
return self._save_json(self.learning_file, categories)
def add_learning_item(self, category_id: int, item: Dict) -> bool:
"""添加学习内容"""
categories = self.get_learning_categories()
for c in categories:
if c['id'] == category_id:
if 'items' not in c:
c['items'] = []
c['items'].append(item)
return self._save_json(self.learning_file, categories)
return False
def update_learning_item(self, category_id: int, item_id: int, data: Dict) -> bool:
"""更新学习内容"""
categories = self.get_learning_categories()
for c in categories:
if c['id'] == category_id:
if 'items' not in c:
return False
for i, item in enumerate(c['items']):
if item['id'] == item_id:
c['items'][i] = {**item, **data}
return self._save_json(self.learning_file, categories)
return False
def delete_learning_item(self, category_id: int, item_id: int) -> bool:
"""删除学习内容"""
categories = self.get_learning_categories()
for c in categories:
if c['id'] == category_id:
if 'items' in c:
c['items'] = [item for item in c['items'] if item['id'] != item_id]
return self._save_json(self.learning_file, categories)
return False
def get_query_categories(self) -> List[Dict]:
"""获取查询分类"""
return self._load_json(self.query_file)
def save_query_category(self, category: Dict) -> bool:
"""保存查询分类"""
categories = self.get_query_categories()
categories.append(category)
return self._save_json(self.query_file, categories)
def update_query_category(self, category_id: int, data: Dict) -> bool:
"""更新查询分类"""
categories = self.get_query_categories()
for i, c in enumerate(categories):
if c['id'] == category_id:
categories[i] = {**c, **data}
return self._save_json(self.query_file, categories)
return False
def delete_query_category(self, category_id: int) -> bool:
"""删除查询分类"""
categories = self.get_query_categories()
categories = [c for c in categories if c['id'] != category_id]
return self._save_json(self.query_file, categories)
def add_query_item(self, category_id: int, item: Dict) -> bool:
"""添加查询内容"""
categories = self.get_query_categories()
for c in categories:
if c['id'] == category_id:
if 'items' not in c:
c['items'] = []
c['items'].append(item)
return self._save_json(self.query_file, categories)
return False
def update_query_item(self, category_id: int, item_id: int, data: Dict) -> bool:
"""更新查询内容"""
categories = self.get_query_categories()
for c in categories:
if c['id'] == category_id:
if 'items' not in c:
return False
for i, item in enumerate(c['items']):
if item['id'] == item_id:
c['items'][i] = {**item, **data}
return self._save_json(self.query_file, categories)
return False
def delete_query_item(self, category_id: int, item_id: int) -> bool:
"""删除查询内容"""
categories = self.get_query_categories()
for c in categories:
if c['id'] == category_id:
if 'items' in c:
c['items'] = [item for item in c['items'] if item['id'] != item_id]
return self._save_json(self.query_file, categories)
return False
def get_deployment_history(self) -> List[Dict]:
"""获取部署历史"""
return self._load_json(self.deployment_file)
def save_deployment_record(self, record: Dict) -> bool:
"""保存部署记录"""
history = self.get_deployment_history()
history.insert(0, record)
if len(history) > 50:
history = history[:50]
return self._save_json(self.deployment_file, history)
def delete_deployment_record(self, record_id: str) -> bool:
"""删除部署记录"""
history = self.get_deployment_history()
history = [r for r in history if r.get('id') != record_id]
return self._save_json(self.deployment_file, history)
def create_task(self, config: Dict) -> str:
"""创建部署任务"""
task_id = str(uuid.uuid4())
task = DeploymentTask(
id=task_id,
status='pending',
config=config,
logs=[]
)
self.tasks[task_id] = task
return task_id
def get_task(self, task_id: str) -> Optional[DeploymentTask]:
"""获取任务"""
return self.tasks.get(task_id)
def update_task_status(self, task_id: str, status: str) -> bool:
"""更新任务状态"""
if task_id in self.tasks:
self.tasks[task_id].status = status
if status == 'running':
self.tasks[task_id].start_time = datetime.now().isoformat()
elif status in ['completed', 'failed', 'cancelled']:
self.tasks[task_id].end_time = datetime.now().isoformat()
return True
return False
def add_task_log(self, task_id: str, level: str, content: str) -> bool:
"""添加任务日志"""
if task_id in self.tasks:
self.tasks[task_id].logs.append({
'timestamp': datetime.now().strftime('%H:%M:%S'),
'level': level,
'content': content
})
return True
return False
data_manager = DataManager()
class DeploymentExecutor:
"""部署执行器"""
def __init__(self, data_manager: DataManager):
self.data_manager = data_manager
def execute_deployment(self, task_id: str):
"""执行部署"""
task = self.data_manager.get_task(task_id)
if not task:
return
config = task.config
self.data_manager.update_task_status(task_id, 'running')
self.data_manager.add_task_log(task_id, 'INFO', f'开始部署任务,任务ID: {task_id}')
try:
self._simulate_deployment(task_id, config)
except Exception as e:
self.data_manager.add_task_log(task_id, 'ERROR', f'部署异常: {str(e)}')
self.data_manager.update_task_status(task_id, 'failed')
def _simulate_deployment(self, task_id: str, config: Dict):
"""模拟部署流程"""
steps = [
('INFO', f'开始连接服务器 {config["server"]}:{config["port"]}...'),
('SUCCESS', f'服务器连接成功,用户: {config["username"]}'),
('INFO', '检查服务器环境...'),
('INFO', '系统版本: Ubuntu 22.04 LTS'),
('INFO', 'CPU: 8核, 内存: 16GB'),
('SUCCESS', '环境检查通过'),
('INFO', f'下载安装脚本 (版本: {config["version"]})...'),
('INFO', '下载进度: [=====> ] 50%'),
('SUCCESS', '脚本下载完成,大小: 2.3MB'),
('INFO', '开始执行安装脚本...'),
('INFO', f'安装组件: {config["components"]}'),
('INFO', '正在安装基础组件...'),
('SUCCESS', '基础组件安装完成'),
]
if 'AI' in config['components']:
steps.append(('INFO', '正在安装 AI 组件...'))
steps.append(('SUCCESS', 'AI 组件安装完成'))
if '监控' in config['components']:
steps.append(('INFO', '正在安装监控组件...'))
steps.append(('SUCCESS', '监控组件安装完成'))
steps.extend([
('INFO', '配置服务...'),
('SUCCESS', '服务配置完成'),
('INFO', '启动服务...'),
('SUCCESS', '服务启动成功'),
('INFO', '运行健康检查...'),
('SUCCESS', '健康检查通过'),
('SUCCESS', '部署完成!服务已就绪'),
])
for level, content in steps:
if self.data_manager.get_task(task_id).status == 'cancelled':
self.data_manager.add_task_log(task_id, 'WARNING', '部署已取消')
return
self.data_manager.add_task_log(task_id, level, content)
time.sleep(0.3 + 0.5 * (hash(content) % 10) / 10)
self.data_manager.update_task_status(task_id, 'completed')
task = self.data_manager.get_task(task_id)
record = {
'id': task_id,
'server': config['server'],
'port': config['port'],
'username': config['username'],
'version': config['version'],
'components': config['components'],
'success': True,
'time': datetime.now().isoformat(),
'logs': task.logs
}
self.data_manager.save_deployment_record(record)
executor = DeploymentExecutor(data_manager)
@app.route('/api/health', methods=['GET'])
def health_check():
"""健康检查"""
return jsonify({'status': 'ok', 'timestamp': datetime.now().isoformat()})
@app.route('/api/modules', methods=['GET'])
def get_modules():
"""获取所有模块"""
return jsonify({'modules': data_manager.get_modules()})
@app.route('/api/modules', methods=['POST'])
def create_module():
"""创建模块"""
data = request.json
module = {
'id': int(time.time() * 1000),
'name': data.get('name'),
'icon': data.get('icon', '📦'),
'desc': data.get('desc'),
'url': data.get('url'),
'enabled': data.get('enabled', True)
}
data_manager.save_module(module)
return jsonify({'success': True, 'module': module})
@app.route('/api/modules/<int:module_id>', methods=['PUT'])
def update_module(module_id):
"""更新模块"""
data = request.json
success = data_manager.update_module(module_id, data)
return jsonify({'success': success})
@app.route('/api/modules/<int:module_id>', methods=['DELETE'])
def delete_module(module_id):
"""删除模块"""
success = data_manager.delete_module(module_id)
return jsonify({'success': success})
@app.route('/api/learning/categories', methods=['GET'])
def get_learning_categories():
"""获取学习分类"""
return jsonify({'categories': data_manager.get_learning_categories()})
@app.route('/api/learning/categories', methods=['POST'])
def create_learning_category():
"""创建学习分类"""
data = request.json
category = {
'id': int(time.time() * 1000),
'name': data.get('name'),
'icon': data.get('icon', '📚'),
'items': []
}
data_manager.save_learning_category(category)
return jsonify({'success': True, 'category': category})
@app.route('/api/learning/categories/<int:category_id>', methods=['PUT'])
def update_learning_category(category_id):
"""更新学习分类"""
data = request.json
success = data_manager.update_learning_category(category_id, data)
return jsonify({'success': success})
@app.route('/api/learning/categories/<int:category_id>', methods=['DELETE'])
def delete_learning_category(category_id):
"""删除学习分类"""
success = data_manager.delete_learning_category(category_id)
return jsonify({'success': success})
@app.route('/api/learning/categories/<int:category_id>/items', methods=['GET'])
def get_learning_items(category_id):
"""获取分类下的内容"""
categories = data_manager.get_learning_categories()
for c in categories:
if c['id'] == category_id:
return jsonify({'items': c.get('items', [])})
return jsonify({'items': []})
@app.route('/api/learning/categories/<int:category_id>/items', methods=['POST'])
def create_learning_item(category_id):
"""创建学习内容"""
data = request.json
item = {
'id': int(time.time() * 1000),
'title': data.get('title'),
'desc': data.get('desc'),
'wiki_url': data.get('wiki_url')
}
success = data_manager.add_learning_item(category_id, item)
return jsonify({'success': success, 'item': item})
@app.route('/api/learning/categories/<int:category_id>/items/<int:item_id>', methods=['PUT'])
def update_learning_item(category_id, item_id):
"""更新学习内容"""
data = request.json
success = data_manager.update_learning_item(category_id, item_id, data)
return jsonify({'success': success})
@app.route('/api/learning/categories/<int:category_id>/items/<int:item_id>', methods=['DELETE'])
def delete_learning_item(category_id, item_id):
"""删除学习内容"""
success = data_manager.delete_learning_item(category_id, item_id)
return jsonify({'success': success})
@app.route('/api/learning/search', methods=['GET'])
def search_learning():
"""搜索学习内容"""
query = request.args.get('q', '').lower()
if not query:
return jsonify({'results': []})
categories = data_manager.get_learning_categories()
results = []
for c in categories:
for item in c.get('items', []):
if query in item.get('title', '').lower() or query in item.get('desc', '').lower():
results.append({
'category': c['name'],
'item': item
})
return jsonify({'results': results})
@app.route('/api/query/categories', methods=['GET'])
def get_query_categories():
"""获取查询分类"""
return jsonify({'categories': data_manager.get_query_categories()})
@app.route('/api/query/categories', methods=['POST'])
def create_query_category():
"""创建查询分类"""
data = request.json
category = {
'id': int(time.time() * 1000),
'name': data.get('name'),
'icon': data.get('icon', '📦'),
'items': []
}
data_manager.save_query_category(category)
return jsonify({'success': True, 'category': category})
@app.route('/api/query/categories/<int:category_id>', methods=['PUT'])
def update_query_category(category_id):
"""更新查询分类"""
data = request.json
success = data_manager.update_query_category(category_id, data)
return jsonify({'success': success})
@app.route('/api/query/categories/<int:category_id>', methods=['DELETE'])
def delete_query_category(category_id):
"""删除查询分类"""
success = data_manager.delete_query_category(category_id)
return jsonify({'success': success})
@app.route('/api/query/categories/<int:category_id>/items', methods=['GET'])
def get_query_items(category_id):
"""获取分类下的内容"""
categories = data_manager.get_query_categories()
for c in categories:
if c['id'] == category_id:
return jsonify({'items': c.get('items', [])})
return jsonify({'items': []})
@app.route('/api/query/categories/<int:category_id>/items', methods=['POST'])
def create_query_item(category_id):
"""创建查询内容"""
data = request.json
item = {
'id': int(time.time() * 1000),
'title': data.get('title'),
'desc': data.get('desc'),
'wiki_url': data.get('wiki_url')
}
success = data_manager.add_query_item(category_id, item)
return jsonify({'success': success, 'item': item})
@app.route('/api/query/categories/<int:category_id>/items/<int:item_id>', methods=['PUT'])
def update_query_item(category_id, item_id):
"""更新查询内容"""
data = request.json
success = data_manager.update_query_item(category_id, item_id, data)
return jsonify({'success': success})
@app.route('/api/query/categories/<int:category_id>/items/<int:item_id>', methods=['DELETE'])
def delete_query_item(category_id, item_id):
"""删除查询内容"""
success = data_manager.delete_query_item(category_id, item_id)
return jsonify({'success': success})
@app.route('/api/query/search', methods=['GET'])
def search_query():
"""搜索查询内容"""
query = request.args.get('q', '').lower()
if not query:
return jsonify({'results': []})
categories = data_manager.get_query_categories()
results = []
for c in categories:
for item in c.get('items', []):
if query in item.get('title', '').lower() or query in item.get('desc', '').lower():
results.append({
'category': c['name'],
'item': item
})
return jsonify({'results': results})
@app.route('/api/deployment/deploy', methods=['POST'])
def deploy():
"""开始部署"""
config = request.json
task_id = data_manager.create_task(config)
thread = threading.Thread(target=executor.execute_deployment, args=(task_id,))
thread.daemon = True
thread.start()
return jsonify({'success': True, 'task_id': task_id})
@app.route('/api/deployment/status/<task_id>', methods=['GET'])
def get_deployment_status(task_id):
"""获取部署状态"""
task = data_manager.get_task(task_id)
if not task:
return jsonify({'error': 'Task not found'}), 404
return jsonify({
'status': task.status,
'start_time': task.start_time,
'end_time': task.end_time
})
@app.route('/api/deployment/logs/<task_id>', methods=['GET'])
def get_deployment_logs(task_id):
"""获取部署日志"""
task = data_manager.get_task(task_id)
if not task:
return jsonify({'error': 'Task not found'}), 404
offset = int(request.args.get('offset', 0))
logs = task.logs[offset:]
return jsonify({'logs': logs, 'total': len(task.logs)})
@app.route('/api/deployment/cancel/<task_id>', methods=['POST'])
def cancel_deployment(task_id):
"""取消部署"""
task = data_manager.get_task(task_id)
if not task:
return jsonify({'error': 'Task not found'}), 404
if task.status in ['pending', 'running']:
data_manager.update_task_status(task_id, 'cancelled')
return jsonify({'success': True})
return jsonify({'error': 'Cannot cancel completed task'}), 400
@app.route('/api/deployment/history', methods=['GET'])
def get_deployment_history():
"""获取部署历史"""
history = data_manager.get_deployment_history()
return jsonify({'history': history})
@app.route('/api/deployment/history/<record_id>', methods=['DELETE'])
def delete_deployment_history(record_id):
"""删除部署记录"""
success = data_manager.delete_deployment_record(record_id)
return jsonify({'success': success})
@app.route('/api/deployment/versions', methods=['GET'])
def get_deployment_versions():
"""获取可用版本"""
versions = [
{'id': 'v2.0', 'name': 'v2.0 - 最新稳定版', 'stable': True},
{'id': 'v1.0', 'name': 'v1.0 - LTS 版本', 'stable': True},
{'id': 'v3.0', 'name': 'v3.0 - 测试版', 'stable': False},
{'id': 'dev', 'name': 'dev - 开发版', 'stable': False}
]
return jsonify({'versions': versions})
@app.route('/api/deployment/components', methods=['GET'])
def get_deployment_components():
"""获取可用组件"""
components = [
{'id': 'base', 'name': '基础组件', 'required': True},
{'id': 'ai', 'name': 'AI 组件', 'required': False},
{'id': 'monitor', 'name': '监控组件', 'required': False},
{'id': 'log', 'name': '日志组件', 'required': False},
{'id': 'cache', 'name': '缓存组件', 'required': False},
{'id': 'ml', 'name': '机器学习组件', 'required': False}
]
return jsonify({'components': components})
@app.errorhandler(404)
def not_found(error):
return jsonify({'error': 'Not found'}), 404
@app.errorhandler(500)
def internal_error(error):
return jsonify({'error': 'Internal server error'}), 500
if __name__ == '__main__':
logger.info("Starting Operator Efficiency Platform Server...")
logger.info(f"Data directory: {DATA_DIR}")
app.run(
host='0.0.0.0',
port=5000,
debug=True,
threaded=True
)