feat: v1.2.0 - 三项优化
1. 模型选择改为两步式:先搜索选择基模型,再选择量化版本 - 自动选中默认量化版本(Q4_K_M),后台可配置 - 模型新增 base_model 字段,按基模型分组 - 后台模型管理增加基模型字段 2. 参数搜索改为全局搜索 - 搜索时跨所有分类显示匹配参数 - 隐藏分类标签页,显示匹配数量 3. 自然语言支持 LLM 接口 - 后台可配置 LLM API (URL/Key/Model/System Prompt) - 启用后优先调用 LLM 解析,失败自动回退正则解析 - 兼容 OpenAI API 格式
This commit is contained in:
@@ -7,6 +7,7 @@ import json
|
||||
import re
|
||||
import math
|
||||
import functools
|
||||
import urllib.request
|
||||
from flask import Flask, request, jsonify, send_from_directory, session, redirect
|
||||
from flask_cors import CORS
|
||||
from db import get_db, init_db, DB_PATH
|
||||
@@ -600,16 +601,86 @@ def get_models():
|
||||
db.close()
|
||||
return jsonify(result)
|
||||
|
||||
@app.route('/api/models/grouped')
|
||||
def get_models_grouped():
|
||||
db = get_db()
|
||||
models = db.execute('SELECT * FROM models ORDER BY base_model, sort_order, name').fetchall()
|
||||
db.close()
|
||||
grouped = {}
|
||||
for m in models:
|
||||
d = dict(m)
|
||||
base = d['base_model']
|
||||
if base not in grouped:
|
||||
grouped[base] = []
|
||||
grouped[base].append(d)
|
||||
# Get default quant from settings
|
||||
db2 = get_db()
|
||||
dq = db2.execute("SELECT value FROM settings WHERE key = 'default_quant'").fetchone()
|
||||
db2.close()
|
||||
default_quant = dq['value'] if dq else 'Q4_K_M'
|
||||
return jsonify({'models': grouped, 'default_quant': default_quant})
|
||||
|
||||
|
||||
# ----- Parse Natural Language -----
|
||||
@app.route('/api/parse-nl', methods=['POST'])
|
||||
def parse_nl():
|
||||
data = request.json
|
||||
text = data.get('text', '')
|
||||
# Try LLM API first if enabled
|
||||
db = get_db()
|
||||
llm_enabled = db.execute("SELECT value FROM settings WHERE key = 'llm_enabled'").fetchone()
|
||||
if llm_enabled and llm_enabled['value'] == 'true':
|
||||
llm_url = db.execute("SELECT value FROM settings WHERE key = 'llm_api_url'").fetchone()
|
||||
llm_key = db.execute("SELECT value FROM settings WHERE key = 'llm_api_key'").fetchone()
|
||||
llm_model = db.execute("SELECT value FROM settings WHERE key = 'llm_api_model'").fetchone()
|
||||
llm_prompt = db.execute("SELECT value FROM settings WHERE key = 'llm_system_prompt'").fetchone()
|
||||
db.close()
|
||||
url = llm_url['value'] if llm_url else ''
|
||||
key = llm_key['value'] if llm_key else ''
|
||||
model = llm_model['value'] if llm_model else ''
|
||||
system_prompt = llm_prompt['value'] if llm_prompt else ''
|
||||
if url:
|
||||
try:
|
||||
result = call_llm_for_parsing(url, key, model, system_prompt, text)
|
||||
if result:
|
||||
return jsonify(result)
|
||||
except Exception as e:
|
||||
print(f'LLM parse failed: {e}', file=sys.stderr)
|
||||
else:
|
||||
db.close()
|
||||
# Fallback to regex parsing
|
||||
result = parse_natural_language(text)
|
||||
return jsonify(result)
|
||||
|
||||
|
||||
def call_llm_for_parsing(url, key, model, system_prompt, user_text):
|
||||
"""Call LLM API to parse natural language into params."""
|
||||
headers = {'Content-Type': 'application/json'}
|
||||
if key:
|
||||
headers['Authorization'] = f'Bearer {key}'
|
||||
body = {
|
||||
'model': model,
|
||||
'messages': [
|
||||
{'role': 'system', 'content': system_prompt},
|
||||
{'role': 'user', 'content': user_text}
|
||||
],
|
||||
'temperature': 0.1,
|
||||
'max_tokens': 2000,
|
||||
}
|
||||
req = urllib.request.Request(url, data=json.dumps(body).encode('utf-8'), headers=headers, method='POST')
|
||||
with urllib.request.urlopen(req, timeout=30) as resp:
|
||||
data = json.loads(resp.read().decode('utf-8'))
|
||||
# OpenAI-compatible response
|
||||
content = data['choices'][0]['message']['content']
|
||||
# Try to extract JSON from the response
|
||||
content = content.strip()
|
||||
if content.startswith('```'):
|
||||
content = re.sub(r'^```\w*\n?', '', content)
|
||||
content = re.sub(r'\n?```$', '', content)
|
||||
result = json.loads(content)
|
||||
return result
|
||||
|
||||
|
||||
# ==================== Admin API ====================
|
||||
|
||||
# All admin routes below require login
|
||||
@@ -800,9 +871,9 @@ def admin_add_model():
|
||||
data = request.json
|
||||
db = get_db()
|
||||
db.execute(
|
||||
'''INSERT INTO models (name, size_gb, layers, embd, kv_heads, head_dim, attention_heads, quant, description, sort_order)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)''',
|
||||
(data['name'], data['size_gb'], data['layers'], data['embd'],
|
||||
'''INSERT INTO models (base_model, name, size_gb, layers, embd, kv_heads, head_dim, attention_heads, quant, description, sort_order)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)''',
|
||||
(data['base_model'], data['name'], data['size_gb'], data['layers'], data['embd'],
|
||||
data['kv_heads'], data['head_dim'], data['attention_heads'],
|
||||
data.get('quant', ''), data.get('description', ''), data.get('sort_order', 0))
|
||||
)
|
||||
@@ -818,9 +889,9 @@ def admin_model_edit(mid):
|
||||
if request.method == 'PUT':
|
||||
data = request.json
|
||||
db.execute(
|
||||
'''UPDATE models SET name=?, size_gb=?, layers=?, embd=?, kv_heads=?,
|
||||
'''UPDATE models SET base_model=?, name=?, size_gb=?, layers=?, embd=?, kv_heads=?,
|
||||
head_dim=?, attention_heads=?, quant=?, description=?, sort_order=? WHERE id=?''',
|
||||
(data['name'], data['size_gb'], data['layers'], data['embd'],
|
||||
(data['base_model'], data['name'], data['size_gb'], data['layers'], data['embd'],
|
||||
data['kv_heads'], data['head_dim'], data['attention_heads'],
|
||||
data.get('quant', ''), data.get('description', ''), data.get('sort_order', 0), mid)
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user