270 lines
7.3 KiB
Python
270 lines
7.3 KiB
Python
"""
|
||
ParamHub - 参数百科
|
||
AI大模型与硬件参数速查平台
|
||
"""
|
||
|
||
from flask import Flask, render_template, jsonify, request
|
||
from flask_cors import CORS
|
||
import json
|
||
from pathlib import Path
|
||
from datetime import datetime
|
||
|
||
app = Flask(__name__, static_folder='static', static_url_path='/static')
|
||
CORS(app)
|
||
|
||
# 数据目录
|
||
DATA_DIR = Path(__file__).parent / 'data'
|
||
DATA_DIR.mkdir(exist_ok=True)
|
||
|
||
# 数据文件
|
||
MODELS_FILE = DATA_DIR / 'models.json'
|
||
GPUS_FILE = DATA_DIR / 'gpus.json'
|
||
CPUS_FILE = DATA_DIR / 'cpus.json'
|
||
|
||
def load_data(file_path):
|
||
"""加载JSON数据"""
|
||
if file_path.exists():
|
||
return json.loads(file_path.read_text(encoding='utf-8'))
|
||
return []
|
||
|
||
def save_data(file_path, data):
|
||
"""保存JSON数据"""
|
||
file_path.write_text(json.dumps(data, ensure_ascii=False, indent=2), encoding='utf-8')
|
||
|
||
# ============ 页面路由 ============
|
||
|
||
@app.route('/')
|
||
def index():
|
||
"""首页"""
|
||
return render_template('index.html')
|
||
|
||
@app.route('/models')
|
||
def models_page():
|
||
"""模型数据库页面"""
|
||
return render_template('models.html')
|
||
|
||
@app.route('/gpus')
|
||
def gpus_page():
|
||
"""GPU数据库页面"""
|
||
return render_template('gpus.html')
|
||
|
||
@app.route('/cpus')
|
||
def cpus_page():
|
||
"""CPU数据库页面"""
|
||
return render_template('cpus.html')
|
||
|
||
@app.route('/tools')
|
||
def tools_page():
|
||
"""工具页面"""
|
||
return render_template('tools.html')
|
||
|
||
@app.route('/compare')
|
||
def compare_page():
|
||
"""对比页面"""
|
||
return render_template('compare.html')
|
||
|
||
@app.route('/knowledge')
|
||
def knowledge_page():
|
||
"""知识库页面"""
|
||
return render_template('knowledge.html')
|
||
|
||
# ============ API路由 ============
|
||
|
||
@app.route('/api/models')
|
||
def api_models():
|
||
"""获取模型列表"""
|
||
models = load_data(MODELS_FILE)
|
||
|
||
# 搜索过滤
|
||
keyword = request.args.get('q', '').strip().lower()
|
||
if keyword:
|
||
models = [m for m in models if keyword in m.get('name', '').lower() or
|
||
keyword in m.get('organization', '').lower()]
|
||
|
||
# 排序
|
||
sort_by = request.args.get('sort', 'name')
|
||
reverse = request.args.get('order', 'asc') == 'desc'
|
||
|
||
if sort_by in ['name', 'parameters', 'context_length', 'mmlu']:
|
||
models = sorted(models, key=lambda x: x.get(sort_by, 0) or 0, reverse=reverse)
|
||
|
||
return jsonify(models)
|
||
|
||
@app.route('/api/models/<model_id>')
|
||
def api_model_detail(model_id):
|
||
"""获取单个模型详情"""
|
||
models = load_data(MODELS_FILE)
|
||
model = next((m for m in models if m['id'] == model_id), None)
|
||
|
||
if not model:
|
||
return jsonify({'error': 'Model not found'}), 404
|
||
|
||
return jsonify(model)
|
||
|
||
@app.route('/api/models', methods=['POST'])
|
||
def api_create_model():
|
||
"""创建新模型"""
|
||
data = request.get_json()
|
||
models = load_data(MODELS_FILE)
|
||
|
||
# 生成ID
|
||
import uuid
|
||
data['id'] = uuid.uuid4().hex[:12]
|
||
data['created_at'] = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
|
||
|
||
models.append(data)
|
||
save_data(MODELS_FILE, models)
|
||
|
||
return jsonify(data)
|
||
|
||
@app.route('/api/models/<model_id>', methods=['PUT'])
|
||
def api_update_model(model_id):
|
||
"""更新模型"""
|
||
data = request.get_json()
|
||
models = load_data(MODELS_FILE)
|
||
|
||
model = next((m for m in models if m['id'] == model_id), None)
|
||
if not model:
|
||
return jsonify({'error': 'Model not found'}), 404
|
||
|
||
model.update(data)
|
||
model['updated_at'] = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
|
||
save_data(MODELS_FILE, models)
|
||
|
||
return jsonify(model)
|
||
|
||
@app.route('/api/models/<model_id>', methods=['DELETE'])
|
||
def api_delete_model(model_id):
|
||
"""删除模型"""
|
||
models = load_data(MODELS_FILE)
|
||
models = [m for m in models if m['id'] != model_id]
|
||
save_data(MODELS_FILE, models)
|
||
|
||
return jsonify({'success': True})
|
||
|
||
@app.route('/api/gpus')
|
||
def api_gpus():
|
||
"""获取GPU列表"""
|
||
gpus = load_data(GPUS_FILE)
|
||
|
||
keyword = request.args.get('q', '').strip().lower()
|
||
if keyword:
|
||
gpus = [g for g in gpus if keyword in g.get('name', '').lower() or
|
||
keyword in g.get('manufacturer', '').lower()]
|
||
|
||
return jsonify(gpus)
|
||
|
||
@app.route('/api/gpus/<gpu_id>')
|
||
def api_gpu_detail(gpu_id):
|
||
"""获取单个GPU详情"""
|
||
gpus = load_data(GPUS_FILE)
|
||
gpu = next((g for g in gpus if g['id'] == gpu_id), None)
|
||
|
||
if not gpu:
|
||
return jsonify({'error': 'GPU not found'}), 404
|
||
|
||
return jsonify(gpu)
|
||
|
||
@app.route('/api/cpus')
|
||
def api_cpus():
|
||
"""获取CPU列表"""
|
||
cpus = load_data(CPUS_FILE)
|
||
|
||
keyword = request.args.get('q', '').strip().lower()
|
||
if keyword:
|
||
cpus = [c for c in cpus if keyword in c.get('name', '').lower() or
|
||
keyword in c.get('manufacturer', '').lower()]
|
||
|
||
return jsonify(cpus)
|
||
|
||
@app.route('/api/cpus/<cpu_id>')
|
||
def api_cpu_detail(cpu_id):
|
||
"""获取单个CPU详情"""
|
||
cpus = load_data(CPUS_FILE)
|
||
cpu = next((c for c in cpus if c['id'] == cpu_id), None)
|
||
|
||
if not cpu:
|
||
return jsonify({'error': 'CPU not found'}), 404
|
||
|
||
return jsonify(cpu)
|
||
|
||
@app.route('/api/search')
|
||
def api_search():
|
||
"""全局搜索"""
|
||
keyword = request.args.get('q', '').strip().lower()
|
||
|
||
if not keyword:
|
||
return jsonify({'models': [], 'gpus': [], 'cpus': []})
|
||
|
||
models = load_data(MODELS_FILE)
|
||
gpus = load_data(GPUS_FILE)
|
||
cpus = load_data(CPUS_FILE)
|
||
|
||
result = {
|
||
'models': [m for m in models if keyword in m.get('name', '').lower() or
|
||
keyword in m.get('organization', '').lower()],
|
||
'gpus': [g for g in gpus if keyword in g.get('name', '').lower() or
|
||
keyword in g.get('manufacturer', '').lower()],
|
||
'cpus': [c for c in cpus if keyword in c.get('name', '').lower() or
|
||
keyword in c.get('manufacturer', '').lower()]
|
||
}
|
||
|
||
return jsonify(result)
|
||
|
||
@app.route('/api/calculate/vram')
|
||
def api_calculate_vram():
|
||
"""显存计算"""
|
||
params = request.args.get('params', '7', type=float) # 参数量(B)
|
||
precision = request.args.get('precision', 'fp16', type=str) # 精度
|
||
|
||
# 计算公式
|
||
# FP32: 参数 * 4字节
|
||
# FP16: 参数 * 2字节
|
||
# INT8: 参数 * 1字节
|
||
# INT4: 参数 * 0.5字节
|
||
|
||
bytes_per_param = {
|
||
'fp32': 4,
|
||
'fp16': 2,
|
||
'int8': 1,
|
||
'int4': 0.5
|
||
}
|
||
|
||
multiplier = bytes_per_param.get(precision, 2)
|
||
vram_gb = params * multiplier * 1e9 / (1024**3) # 转换为GB
|
||
|
||
# 加上KV cache和激活值估算(约30%额外开销)
|
||
total_vram = vram_gb * 1.3
|
||
|
||
# 推荐GPU
|
||
gpus = load_data(GPUS_FILE)
|
||
suitable_gpus = [g for g in gpus if g.get('memory_gb', 0) >= total_vram]
|
||
|
||
return jsonify({
|
||
'model_vram': round(vram_gb, 2),
|
||
'total_vram': round(total_vram, 2),
|
||
'suitable_gpus': suitable_gpus
|
||
})
|
||
|
||
@app.route('/api/stats')
|
||
def api_stats():
|
||
"""统计数据"""
|
||
models = load_data(MODELS_FILE)
|
||
gpus = load_data(GPUS_FILE)
|
||
cpus = load_data(CPUS_FILE)
|
||
|
||
return jsonify({
|
||
'models_count': len(models),
|
||
'gpus_count': len(gpus),
|
||
'cpus_count': len(cpus),
|
||
'latest_models': sorted(models, key=lambda x: x.get('created_at', ''), reverse=True)[:5]
|
||
})
|
||
|
||
if __name__ == '__main__':
|
||
print("=" * 50)
|
||
print("ParamHub - 参数百科")
|
||
print("=" * 50)
|
||
print(f"访问地址: http://localhost:19010")
|
||
print("=" * 50)
|
||
|
||
app.run(host='0.0.0.0', port=19010, debug=True) |