Files
param-hub-python/app.py
hubian dfd7234fd6 fix: 修复模型排序错误,改名为大模型管理
- 修复智能添加创建的不完整数据导致排序错误
- 添加安全排序函数处理缺失字段
- 改名:模型管理 → 大模型管理
- 清理测试数据
2026-04-11 02:06:06 +08:00

874 lines
27 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""
ParamHub - 参数百科
AI大模型与硬件参数速查平台
v1.1.0 - 新增智能添加和展示开关功能
"""
from flask import Flask, render_template, jsonify, request
from flask_cors import CORS
import json
import requests
from pathlib import Path
from datetime import datetime
import uuid
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'
CATEGORIES_FILE = DATA_DIR / 'categories.json'
KNOWLEDGE_FILE = DATA_DIR / 'knowledge.json'
# 大模型配置
LLM_CONFIG = {
'base_url': 'http://192.168.2.17:19007/v1',
'api_key': 'xxxx',
'model': 'auto',
}
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')
# ============ 大模型智能解析 ============
def parse_with_llm(text, category_type):
"""
使用大模型解析文本,提取结构化数据
"""
# 根据类型定义字段模板
field_templates = {
'model': {
'name': '模型名称',
'organization': '厂商/组织',
'parameters': '参数量(数字单位B)',
'context_length': '上下文长度(数字)',
'architecture': '架构类型',
'is_open_source': '是否开源(true/false)',
'mmlu': 'MMLU分数(数字)',
'input_price': '输入价格(数字)',
'output_price': '输出价格(数字)',
'license': '许可证',
'description': '简介描述',
},
'gpu': {
'name': 'GPU名称',
'manufacturer': '厂商',
'architecture': '架构',
'memory_gb': '显存大小(数字单位GB)',
'cuda_cores': 'CUDA核心数(数字)',
'tensor_cores': 'Tensor核心数(数字)',
'memory_bandwidth_gbs': '显存带宽(数字单位GB/s)',
'fp16_tflops': 'FP16性能(数字单位TF)',
'price_usd': '价格(数字)',
'release_year': '发布年份(数字)',
'description': '简介描述',
},
'cpu': {
'name': 'CPU名称',
'manufacturer': '厂商',
'architecture': '架构',
'cores': '核心数(数字)',
'threads': '线程数(数字)',
'base_clock_ghz': '基础频率(数字单位GHz)',
'boost_clock_ghz': '加速频率(数字单位GHz)',
'l3_cache_mb': 'L3缓存(数字单位MB)',
'tdp_watts': 'TDP功耗(数字单位W)',
'price_usd': '价格(数字)',
'description': '简介描述',
},
'dynamic': {
'name': '名称',
'brand': '品牌',
'price': '价格(数字)',
'year': '年份(数字)',
'specs': '规格参数',
'description': '简介描述',
},
}
fields = field_templates.get(category_type, field_templates['dynamic'])
prompt = f"""请解析以下文本,提取结构化数据。
文本内容:
{text}
需要提取的字段:
{json.dumps(fields, ensure_ascii=False, indent=2)}
要求:
1. 根据文本内容智能提取各个字段的值
2. 数字字段只返回数字,不带单位
3. 如果某字段在文本中没有提及返回null
4. 返回JSON格式不要包含任何其他内容
请直接返回JSON数据"""
try:
response = requests.post(
f"{LLM_CONFIG['base_url']}/chat/completions",
headers={
"Content-Type": "application/json",
"Authorization": f"Bearer {LLM_CONFIG['api_key']}"
},
json={
"model": LLM_CONFIG['model'],
"messages": [
{"role": "system", "content": "你是一个数据提取助手负责从文本中提取结构化数据。只返回JSON不要其他内容。"},
{"role": "user", "content": prompt}
],
"max_tokens": 1000,
"temperature": 0.1
},
timeout=30
)
if response.status_code == 200:
data = response.json()
content = data['choices'][0]['message']['content'].strip()
# 清理可能的markdown包裹
if content.startswith('```'):
content = content.split('\n', 1)[1] if '\n' in content else content[3:]
content = content.rsplit('```', 1)[0] if '```' in content else content
# 解析JSON
parsed = json.loads(content)
# 清理null值
cleaned = {}
for k, v in parsed.items():
if v is not None and v != '' and v != 'null':
# 尝试转换数字
if isinstance(v, str):
try:
if '.' in v:
cleaned[k] = float(v)
else:
cleaned[k] = int(v)
except:
cleaned[k] = v
else:
cleaned[k] = v
return cleaned
except Exception as e:
print(f"LLM解析失败: {e}")
# 降级处理:返回基本结构
return {'name': text[:50], 'description': text}
# ============ 页面路由 ============
@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')
@app.route('/admin')
def admin_page():
"""后台管理页面"""
return render_template('admin.html')
@app.route('/category/<category_id>')
def category_page(category_id):
"""动态分类页面"""
categories = load_data(CATEGORIES_FILE)
category = next((c for c in categories if c['id'] == category_id), None)
if not category:
return "分类不存在", 404
return render_template('category.html', category=category)
# ============ API路由 ============
@app.route('/api/models')
def api_models():
"""获取模型列表"""
models = load_data(MODELS_FILE)
# 过滤隐藏项前台默认不显示visible=false
hide_hidden = request.args.get('all', '0') == '0'
if hide_hidden:
models = [m for m in models if m.get('visible', True)]
# 搜索过滤
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', 'created_at')
reverse = request.args.get('order', 'asc') == 'desc'
# 安全排序处理可能的None/缺失值
def safe_sort_key(x, key):
val = x.get(key)
if val is None:
return 0 if key in ['parameters', 'context_length', 'mmlu'] else ''
return val
if sort_by in ['name', 'parameters', 'context_length', 'mmlu', 'created_at']:
models = sorted(models, key=lambda x: safe_sort_key(x, sort_by), 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)
data['id'] = uuid.uuid4().hex[:12]
data['created_at'] = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
data['visible'] = data.get('visible', True) # 默认显示
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/models/<model_id>/visible', methods=['POST'])
def api_toggle_model_visible(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
model['visible'] = not model.get('visible', True)
save_data(MODELS_FILE, models)
return jsonify({'success': True, 'visible': model['visible']})
# ============ 智能添加API ============
@app.route('/api/models/smart-add', methods=['POST'])
def api_smart_add_model():
"""智能添加模型(粘贴文本解析)"""
data = request.get_json()
text = data.get('text', '')
if not text:
return jsonify({'error': '文本不能为空'}), 400
# 大模型解析
parsed = parse_with_llm(text, 'model')
# 补充必要字段
parsed['id'] = uuid.uuid4().hex[:12]
parsed['created_at'] = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
parsed['visible'] = True
parsed['raw_text'] = text # 保存原始文本
# 保存
models = load_data(MODELS_FILE)
models.append(parsed)
save_data(MODELS_FILE, models)
return jsonify(parsed)
@app.route('/api/gpus/smart-add', methods=['POST'])
def api_smart_add_gpu():
"""智能添加GPU"""
data = request.get_json()
text = data.get('text', '')
if not text:
return jsonify({'error': '文本不能为空'}), 400
parsed = parse_with_llm(text, 'gpu')
parsed['id'] = uuid.uuid4().hex[:12]
parsed['created_at'] = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
parsed['visible'] = True
parsed['raw_text'] = text
gpus = load_data(GPUS_FILE)
gpus.append(parsed)
save_data(GPUS_FILE, gpus)
return jsonify(parsed)
@app.route('/api/cpus/smart-add', methods=['POST'])
def api_smart_add_cpu():
"""智能添加CPU"""
data = request.get_json()
text = data.get('text', '')
if not text:
return jsonify({'error': '文本不能为空'}), 400
parsed = parse_with_llm(text, 'cpu')
parsed['id'] = uuid.uuid4().hex[:12]
parsed['created_at'] = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
parsed['visible'] = True
parsed['raw_text'] = text
cpus = load_data(CPUS_FILE)
cpus.append(parsed)
save_data(CPUS_FILE, cpus)
return jsonify(parsed)
@app.route('/api/items/<category_id>/smart-add', methods=['POST'])
def api_smart_add_item(category_id):
"""智能添加动态分类数据"""
data = request.get_json()
text = data.get('text', '')
if not text:
return jsonify({'error': '文本不能为空'}), 400
parsed = parse_with_llm(text, 'dynamic')
parsed['id'] = uuid.uuid4().hex[:12]
parsed['category_id'] = category_id
parsed['created_at'] = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
parsed['visible'] = True
parsed['raw_text'] = text
items_file = DATA_DIR / f'items_{category_id}.json'
items = load_data(items_file)
items.append(parsed)
save_data(items_file, items)
return jsonify(parsed)
# ============ GPU API ============
@app.route('/api/gpus')
def api_gpus():
"""获取GPU列表"""
gpus = load_data(GPUS_FILE)
# 过滤隐藏项
hide_hidden = request.args.get('all', '0') == '0'
if hide_hidden:
gpus = [g for g in gpus if g.get('visible', True)]
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/gpus', methods=['POST'])
def api_create_gpu():
"""创建新GPU"""
data = request.get_json()
gpus = load_data(GPUS_FILE)
data['id'] = uuid.uuid4().hex[:12]
data['created_at'] = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
data['visible'] = data.get('visible', True)
gpus.append(data)
save_data(GPUS_FILE, gpus)
return jsonify(data)
@app.route('/api/gpus/<gpu_id>', methods=['PUT'])
def api_update_gpu(gpu_id):
"""更新GPU"""
data = request.get_json()
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
gpu.update(data)
gpu['updated_at'] = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
save_data(GPUS_FILE, gpus)
return jsonify(gpu)
@app.route('/api/gpus/<gpu_id>', methods=['DELETE'])
def api_delete_gpu(gpu_id):
"""删除GPU"""
gpus = load_data(GPUS_FILE)
gpus = [g for g in gpus if g['id'] != gpu_id]
save_data(GPUS_FILE, gpus)
return jsonify({'success': True})
@app.route('/api/gpus/<gpu_id>/visible', methods=['POST'])
def api_toggle_gpu_visible(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
gpu['visible'] = not gpu.get('visible', True)
save_data(GPUS_FILE, gpus)
return jsonify({'success': True, 'visible': gpu['visible']})
# ============ CPU API ============
@app.route('/api/cpus')
def api_cpus():
"""获取CPU列表"""
cpus = load_data(CPUS_FILE)
# 过滤隐藏项
hide_hidden = request.args.get('all', '0') == '0'
if hide_hidden:
cpus = [c for c in cpus if c.get('visible', True)]
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/cpus', methods=['POST'])
def api_create_cpu():
"""创建新CPU"""
data = request.get_json()
cpus = load_data(CPUS_FILE)
data['id'] = uuid.uuid4().hex[:12]
data['created_at'] = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
data['visible'] = data.get('visible', True)
cpus.append(data)
save_data(CPUS_FILE, cpus)
return jsonify(data)
@app.route('/api/cpus/<cpu_id>', methods=['PUT'])
def api_update_cpu(cpu_id):
"""更新CPU"""
data = request.get_json()
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
cpu.update(data)
cpu['updated_at'] = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
save_data(CPUS_FILE, cpus)
return jsonify(cpu)
@app.route('/api/cpus/<cpu_id>', methods=['DELETE'])
def api_delete_cpu(cpu_id):
"""删除CPU"""
cpus = load_data(CPUS_FILE)
cpus = [c for c in cpus if c['id'] != cpu_id]
save_data(CPUS_FILE, cpus)
return jsonify({'success': True})
@app.route('/api/cpus/<cpu_id>/visible', methods=['POST'])
def api_toggle_cpu_visible(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
cpu['visible'] = not cpu.get('visible', True)
save_data(CPUS_FILE, cpus)
return jsonify({'success': True, 'visible': cpu['visible']})
# ============ 搜索和其他API ============
@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 m.get('visible', True) and (keyword in m.get('name', '').lower() or keyword in m.get('organization', '').lower())],
'gpus': [g for g in gpus if g.get('visible', True) and (keyword in g.get('name', '').lower() or keyword in g.get('manufacturer', '').lower())],
'cpus': [c for c in cpus if c.get('visible', True) and (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)
precision = request.args.get('precision', 'fp16', type=str)
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)
total_vram = vram_gb * 1.3
gpus = load_data(GPUS_FILE)
suitable_gpus = [g for g in gpus if g.get('visible', True) and 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)
categories = load_data(CATEGORIES_FILE)
knowledge = load_data(KNOWLEDGE_FILE)
return jsonify({
'models_count': len([m for m in models if m.get('visible', True)]),
'gpus_count': len([g for g in gpus if g.get('visible', True)]),
'cpus_count': len([c for c in cpus if c.get('visible', True)]),
'categories_count': len([c for c in categories if c.get('visible', True)]),
'knowledge_count': len(knowledge),
'latest_models': sorted([m for m in models if m.get('visible', True)], key=lambda x: x.get('created_at', ''), reverse=True)[:5]
})
# ============ 分类管理API ============
@app.route('/api/categories')
def api_categories():
"""获取分类列表"""
categories = load_data(CATEGORIES_FILE)
# 过滤隐藏项
hide_hidden = request.args.get('all', '0') == '0'
if hide_hidden:
categories = [c for c in categories if c.get('visible', True)]
return jsonify(sorted(categories, key=lambda x: x.get('order', 0)))
@app.route('/api/categories', methods=['POST'])
def api_create_category():
"""创建新分类"""
data = request.get_json()
categories = load_data(CATEGORIES_FILE)
data['id'] = uuid.uuid4().hex[:12]
data['created_at'] = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
data['visible'] = data.get('visible', True)
categories.append(data)
save_data(CATEGORIES_FILE, categories)
return jsonify(data)
@app.route('/api/categories/<category_id>', methods=['PUT'])
def api_update_category(category_id):
"""更新分类"""
data = request.get_json()
categories = load_data(CATEGORIES_FILE)
category = next((c for c in categories if c['id'] == category_id), None)
if not category:
return jsonify({'error': 'Category not found'}), 404
category.update(data)
category['updated_at'] = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
save_data(CATEGORIES_FILE, categories)
return jsonify(category)
@app.route('/api/categories/<category_id>', methods=['DELETE'])
def api_delete_category(category_id):
"""删除分类"""
categories = load_data(CATEGORIES_FILE)
categories = [c for c in categories if c['id'] != category_id]
save_data(CATEGORIES_FILE, categories)
return jsonify({'success': True})
@app.route('/api/categories/<category_id>/visible', methods=['POST'])
def api_toggle_category_visible(category_id):
"""切换分类显示状态"""
categories = load_data(CATEGORIES_FILE)
category = next((c for c in categories if c['id'] == category_id), None)
if not category:
return jsonify({'error': 'Category not found'}), 404
category['visible'] = not category.get('visible', True)
save_data(CATEGORIES_FILE, categories)
return jsonify({'success': True, 'visible': category['visible']})
# ============ 知识库管理API ============
@app.route('/api/knowledge')
def api_knowledge():
"""获取知识列表"""
knowledge = load_data(KNOWLEDGE_FILE)
keyword = request.args.get('q', '').strip().lower()
if keyword:
knowledge = [k for k in knowledge if keyword in k.get('title', '').lower() or keyword in k.get('content', '').lower()]
category = request.args.get('category', '')
if category:
knowledge = [k for k in knowledge if k.get('category') == category]
return jsonify(sorted(knowledge, key=lambda x: x.get('order', 0)))
@app.route('/api/knowledge/<knowledge_id>')
def api_knowledge_detail(knowledge_id):
"""获取单个知识详情"""
knowledge = load_data(KNOWLEDGE_FILE)
item = next((k for k in knowledge if k['id'] == knowledge_id), None)
if not item:
return jsonify({'error': 'Knowledge not found'}), 404
return jsonify(item)
@app.route('/api/knowledge', methods=['POST'])
def api_create_knowledge():
"""创建新知识"""
data = request.get_json()
knowledge = load_data(KNOWLEDGE_FILE)
data['id'] = uuid.uuid4().hex[:12]
data['created_at'] = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
if 'order' not in data:
data['order'] = len(knowledge)
knowledge.append(data)
save_data(KNOWLEDGE_FILE, knowledge)
return jsonify(data)
@app.route('/api/knowledge/<knowledge_id>', methods=['PUT'])
def api_update_knowledge(knowledge_id):
"""更新知识"""
data = request.get_json()
knowledge = load_data(KNOWLEDGE_FILE)
item = next((k for k in knowledge if k['id'] == knowledge_id), None)
if not item:
return jsonify({'error': 'Knowledge not found'}), 404
item.update(data)
item['updated_at'] = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
save_data(KNOWLEDGE_FILE, knowledge)
return jsonify(item)
@app.route('/api/knowledge/<knowledge_id>', methods=['DELETE'])
def api_delete_knowledge(knowledge_id):
"""删除知识"""
knowledge = load_data(KNOWLEDGE_FILE)
knowledge = [k for k in knowledge if k['id'] != knowledge_id]
save_data(KNOWLEDGE_FILE, knowledge)
return jsonify({'success': True})
# ============ 动态分类数据API ============
@app.route('/api/items/<category_id>')
def api_items(category_id):
"""获取分类下的数据列表"""
items_file = DATA_DIR / f'items_{category_id}.json'
items = load_data(items_file)
# 过滤隐藏项
hide_hidden = request.args.get('all', '0') == '0'
if hide_hidden:
items = [i for i in items if i.get('visible', True)]
return jsonify(items)
@app.route('/api/items/<category_id>/<item_id>')
def api_item_detail(category_id, item_id):
"""获取单个数据详情"""
items_file = DATA_DIR / f'items_{category_id}.json'
items = load_data(items_file)
item = next((i for i in items if i['id'] == item_id), None)
if not item:
return jsonify({'error': 'Item not found'}), 404
return jsonify(item)
@app.route('/api/items/<category_id>', methods=['POST'])
def api_create_item(category_id):
"""创建新数据"""
data = request.get_json()
items_file = DATA_DIR / f'items_{category_id}.json'
items = load_data(items_file)
data['id'] = uuid.uuid4().hex[:12]
data['category_id'] = category_id
data['created_at'] = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
data['visible'] = data.get('visible', True)
items.append(data)
save_data(items_file, items)
return jsonify(data)
@app.route('/api/items/<category_id>/<item_id>', methods=['PUT'])
def api_update_item(category_id, item_id):
"""更新数据"""
data = request.get_json()
items_file = DATA_DIR / f'items_{category_id}.json'
items = load_data(items_file)
item = next((i for i in items if i['id'] == item_id), None)
if not item:
return jsonify({'error': 'Item not found'}), 404
item.update(data)
item['updated_at'] = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
save_data(items_file, items)
return jsonify(item)
@app.route('/api/items/<category_id>/<item_id>', methods=['DELETE'])
def api_delete_item(category_id, item_id):
"""删除数据"""
items_file = DATA_DIR / f'items_{category_id}.json'
items = load_data(items_file)
items = [i for i in items if i['id'] != item_id]
save_data(items_file, items)
return jsonify({'success': True})
@app.route('/api/items/<category_id>/<item_id>/visible', methods=['POST'])
def api_toggle_item_visible(category_id, item_id):
"""切换动态数据显示状态"""
items_file = DATA_DIR / f'items_{category_id}.json'
items = load_data(items_file)
item = next((i for i in items if i['id'] == item_id), None)
if not item:
return jsonify({'error': 'Item not found'}), 404
item['visible'] = not item.get('visible', True)
save_data(items_file, items)
return jsonify({'success': True, 'visible': item['visible']})
if __name__ == '__main__':
print("=" * 50)
print("ParamHub - 参数百科 v1.1.0")
print("=" * 50)
print(f"访问地址: http://localhost:19010")
print(f"后台管理: http://localhost:19010/admin")
print("=" * 50)
app.run(host='0.0.0.0', port=19010, debug=True)