diff --git a/app.py b/app.py index f1ce2cc..51049b0 100644 --- a/app.py +++ b/app.py @@ -621,6 +621,15 @@ def get_models_grouped(): return jsonify({'models': grouped, 'default_quant': default_quant}) +# ----- Public Settings (only nl_default_text) ----- +@app.route('/api/settings/public') +def get_public_settings(): + db = get_db() + nl = db.execute("SELECT value FROM settings WHERE key = 'nl_default_text'").fetchone() + db.close() + return jsonify({'nl_default_text': nl['value'] if nl else ''}) + + # ----- Parse Natural Language ----- @app.route('/api/parse-nl', methods=['POST']) def parse_nl(): @@ -871,11 +880,11 @@ def admin_add_model(): data = request.json db = get_db() db.execute( - '''INSERT INTO models (base_model, name, size_gb, layers, embd, kv_heads, head_dim, attention_heads, quant, description, sort_order) - VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)''', + '''INSERT INTO models (base_model, name, size_gb, layers, embd, kv_heads, head_dim, attention_heads, default_ctx, 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)) + data.get('default_ctx', 0), data.get('quant', ''), data.get('description', ''), data.get('sort_order', 0)) ) db.commit() db.close() @@ -890,10 +899,10 @@ def admin_model_edit(mid): data = request.json db.execute( '''UPDATE models SET base_model=?, name=?, size_gb=?, layers=?, embd=?, kv_heads=?, - head_dim=?, attention_heads=?, quant=?, description=?, sort_order=? WHERE id=?''', + head_dim=?, attention_heads=?, default_ctx=?, quant=?, description=?, sort_order=? WHERE id=?''', (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) + data.get('default_ctx', 0), data.get('quant', ''), data.get('description', ''), data.get('sort_order', 0), mid) ) db.commit() db.close() diff --git a/db.py b/db.py index 2a7a0b4..b00be63 100644 --- a/db.py +++ b/db.py @@ -88,6 +88,7 @@ def init_db(): kv_heads INTEGER NOT NULL, head_dim INTEGER NOT NULL, attention_heads INTEGER NOT NULL, + default_ctx INTEGER DEFAULT 0, quant TEXT DEFAULT '', description TEXT DEFAULT '', sort_order INTEGER DEFAULT 0 @@ -313,66 +314,66 @@ def insert_default_data(conn): (v2_id,) + p) # ===== Default models ===== - # (base_model, name, size_gb, layers, embd, kv_heads, head_dim, attention_heads, quant, description, sort_order) + # (base_model, name, size_gb, layers, embd, kv_heads, head_dim, attention_heads, default_ctx, quant, description, sort_order) default_models = [ - # Llama-3-8B-Instruct - ("Llama-3-8B-Instruct", "Llama-3-8B-Instruct (Q4_K_M)", 4.9, 32, 4096, 8, 128, 32, "Q4_K_M", "Meta Llama 3 8B Instruct, Q4_K_M 量化", 1), - ("Llama-3-8B-Instruct", "Llama-3-8B-Instruct (Q8_0)", 8.5, 32, 4096, 8, 128, 32, "Q8_0", "Meta Llama 3 8B Instruct, Q8_0 量化", 2), - ("Llama-3-8B-Instruct", "Llama-3-8B-Instruct (FP16)", 15.5, 32, 4096, 8, 128, 32, "FP16", "Meta Llama 3 8B Instruct, FP16", 3), - # Llama-3-70B-Instruct - ("Llama-3-70B-Instruct", "Llama-3-70B-Instruct (Q4_K_M)", 38.5, 80, 8192, 8, 128, 64, "Q4_K_M", "Meta Llama 3 70B Instruct, Q4_K_M 量化", 4), - ("Llama-3-70B-Instruct", "Llama-3-70B-Instruct (Q8_0)", 74.0, 80, 8192, 8, 128, 64, "Q8_0", "Meta Llama 3 70B Instruct, Q8_0 量化", 5), - ("Llama-3-70B-Instruct", "Llama-3-70B-Instruct (FP16)", 138.0, 80, 8192, 8, 128, 64, "FP16", "Meta Llama 3 70B Instruct, FP16", 6), - # Llama-3.1-8B-Instruct - ("Llama-3.1-8B-Instruct", "Llama-3.1-8B-Instruct (Q4_K_M)", 4.9, 32, 4096, 8, 128, 32, "Q4_K_M", "Meta Llama 3.1 8B Instruct, Q4_K_M 量化", 7), - ("Llama-3.1-8B-Instruct", "Llama-3.1-8B-Instruct (Q8_0)", 8.5, 32, 4096, 8, 128, 32, "Q8_0", "Meta Llama 3.1 8B Instruct, Q8_0 量化", 8), - # Llama-3.1-70B-Instruct - ("Llama-3.1-70B-Instruct", "Llama-3.1-70B-Instruct (Q4_K_M)", 38.5, 80, 8192, 8, 128, 64, "Q4_K_M", "Meta Llama 3.1 70B Instruct, Q4_K_M 量化", 9), - ("Llama-3.1-70B-Instruct", "Llama-3.1-70B-Instruct (Q8_0)", 74.0, 80, 8192, 8, 128, 64, "Q8_0", "Meta Llama 3.1 70B Instruct, Q8_0 量化", 10), - # Llama-3.1-405B-Instruct - ("Llama-3.1-405B-Instruct", "Llama-3.1-405B-Instruct (Q4_K_M)", 226.0, 126, 16384, 8, 128, 128, "Q4_K_M", "Meta Llama 3.1 405B Instruct, Q4_K_M 量化", 11), - # Qwen2.5-7B-Instruct - ("Qwen2.5-7B-Instruct", "Qwen2.5-7B-Instruct (Q4_K_M)", 4.7, 28, 3584, 4, 128, 28, "Q4_K_M", "Qwen2.5 7B Instruct, Q4_K_M 量化", 12), - ("Qwen2.5-7B-Instruct", "Qwen2.5-7B-Instruct (Q8_0)", 7.6, 28, 3584, 4, 128, 28, "Q8_0", "Qwen2.5 7B Instruct, Q8_0 量化", 13), - # Qwen2.5-14B-Instruct - ("Qwen2.5-14B-Instruct", "Qwen2.5-14B-Instruct (Q4_K_M)", 8.7, 40, 5120, 8, 128, 40, "Q4_K_M", "Qwen2.5 14B Instruct, Q4_K_M 量化", 14), - # Qwen2.5-32B-Instruct - ("Qwen2.5-32B-Instruct", "Qwen2.5-32B-Instruct (Q4_K_M)", 19.5, 64, 5120, 8, 128, 64, "Q4_K_M", "Qwen2.5 32B Instruct, Q4_K_M 量化", 15), - ("Qwen2.5-32B-Instruct", "Qwen2.5-32B-Instruct (Q8_0)", 32.0, 64, 5120, 8, 128, 64, "Q8_0", "Qwen2.5 32B Instruct, Q8_0 量化", 16), - # Qwen2.5-72B-Instruct - ("Qwen2.5-72B-Instruct", "Qwen2.5-72B-Instruct (Q4_K_M)", 42.0, 80, 8192, 8, 128, 64, "Q4_K_M", "Qwen2.5 72B Instruct, Q4_K_M 量化", 17), - ("Qwen2.5-72B-Instruct", "Qwen2.5-72B-Instruct (Q8_0)", 75.0, 80, 8192, 8, 128, 64, "Q8_0", "Qwen2.5 72B Instruct, Q8_0 量化", 18), - # DeepSeek-V2-Chat - ("DeepSeek-V2-Chat", "DeepSeek-V2-Chat (Q4_K_M)", 23.0, 60, 5120, 8, 128, 60, "Q4_K_M", "DeepSeek V2 Chat, Q4_K_M 量化", 19), - # DeepSeek-V2.5-Chat - ("DeepSeek-V2.5-Chat", "DeepSeek-V2.5-Chat (Q4_K_M)", 23.0, 60, 5120, 8, 128, 60, "Q4_K_M", "DeepSeek V2.5 Chat, Q4_K_M 量化", 20), - # DeepSeek-R1-Distill-Qwen-32B - ("DeepSeek-R1-Distill-Qwen-32B", "DeepSeek-R1-Distill-Qwen-32B (Q4_K_M)", 19.5, 64, 5120, 8, 128, 64, "Q4_K_M", "DeepSeek R1 Distill Qwen 32B, Q4_K_M 量化", 21), - ("DeepSeek-R1-Distill-Qwen-32B", "DeepSeek-R1-Distill-Qwen-32B (Q8_0)", 32.0, 64, 5120, 8, 128, 64, "Q8_0", "DeepSeek R1 Distill Qwen 32B, Q8_0 量化", 22), - # DeepSeek-R1-Distill-Llama-70B - ("DeepSeek-R1-Distill-Llama-70B", "DeepSeek-R1-Distill-Llama-70B (Q4_K_M)", 42.0, 80, 8192, 8, 128, 64, "Q4_K_M", "DeepSeek R1 Distill Llama 70B, Q4_K_M 量化", 23), - ("DeepSeek-R1-Distill-Llama-70B", "DeepSeek-R1-Distill-Llama-70B (Q8_0)", 75.0, 80, 8192, 8, 128, 64, "Q8_0", "DeepSeek R1 Distill Llama 70B, Q8_0 量化", 24), - # Mistral-7B-Instruct-v0.3 - ("Mistral-7B-Instruct-v0.3", "Mistral-7B-Instruct-v0.3 (Q4_K_M)", 4.4, 32, 4096, 8, 128, 32, "Q4_K_M", "Mistral 7B Instruct v0.3, Q4_K_M 量化", 25), - ("Mistral-7B-Instruct-v0.3", "Mistral-7B-Instruct-v0.3 (Q8_0)", 7.5, 32, 4096, 8, 128, 32, "Q8_0", "Mistral 7B Instruct v0.3, Q8_0 量化", 26), - # Mixtral-8x7B-Instruct - ("Mixtral-8x7B-Instruct", "Mixtral-8x7B-Instruct (Q4_K_M)", 26.0, 32, 4096, 8, 128, 32, "Q4_K_M", "Mixtral 8x7B Instruct, Q4_K_M 量化", 27), - # Gemma-2-9B-It - ("Gemma-2-9B-It", "Gemma-2-9B-It (Q4_K_M)", 5.4, 42, 3584, 4, 256, 14, "Q4_K_M", "Google Gemma 2 9B It, Q4_K_M 量化", 28), - # Gemma-2-27B-It - ("Gemma-2-27B-It", "Gemma-2-27B-It (Q4_K_M)", 16.5, 46, 4608, 4, 128, 36, "Q4_K_M", "Google Gemma 2 27B It, Q4_K_M 量化", 29), - # Phi-3-Mini-4K-Instruct - ("Phi-3-Mini-4K-Instruct", "Phi-3-Mini-4K-Instruct (Q4_K_M)", 2.5, 32, 3072, 32, 96, 32, "Q4_K_M", "Microsoft Phi-3 Mini 4K Instruct, Q4_K_M 量化", 30), - # Phi-3-Medium-14B-Instruct - ("Phi-3-Medium-14B-Instruct", "Phi-3-Medium-14B-Instruct (Q4_K_M)", 8.4, 40, 5120, 10, 128, 40, "Q4_K_M", "Microsoft Phi-3 Medium 14B Instruct, Q4_K_M 量化", 31), - # GLM-4-9B-Chat - ("GLM-4-9B-Chat", "GLM-4-9B-Chat (Q4_K_M)", 5.5, 40, 4096, 4, 128, 40, "Q4_K_M", "Zhipu GLM-4 9B Chat, Q4_K_M 量化", 32), - ("GLM-4-9B-Chat", "GLM-4-9B-Chat (Q8_0)", 9.0, 40, 4096, 4, 128, 40, "Q8_0", "Zhipu GLM-4 9B Chat, Q8_0 量化", 33), + # Llama-3-8B-Instruct (ctx 8192) + ("Llama-3-8B-Instruct", "Llama-3-8B-Instruct (Q4_K_M)", 4.9, 32, 4096, 8, 128, 32, 8192, "Q4_K_M", "Meta Llama 3 8B Instruct, Q4_K_M 量化", 1), + ("Llama-3-8B-Instruct", "Llama-3-8B-Instruct (Q8_0)", 8.5, 32, 4096, 8, 128, 32, 8192, "Q8_0", "Meta Llama 3 8B Instruct, Q8_0 量化", 2), + ("Llama-3-8B-Instruct", "Llama-3-8B-Instruct (FP16)", 15.5, 32, 4096, 8, 128, 32, 8192, "FP16", "Meta Llama 3 8B Instruct, FP16", 3), + # Llama-3-70B-Instruct (ctx 8192) + ("Llama-3-70B-Instruct", "Llama-3-70B-Instruct (Q4_K_M)", 38.5, 80, 8192, 8, 128, 64, 8192, "Q4_K_M", "Meta Llama 3 70B Instruct, Q4_K_M 量化", 4), + ("Llama-3-70B-Instruct", "Llama-3-70B-Instruct (Q8_0)", 74.0, 80, 8192, 8, 128, 64, 8192, "Q8_0", "Meta Llama 3 70B Instruct, Q8_0 量化", 5), + ("Llama-3-70B-Instruct", "Llama-3-70B-Instruct (FP16)", 138.0, 80, 8192, 8, 128, 64, 8192, "FP16", "Meta Llama 3 70B Instruct, FP16", 6), + # Llama-3.1-8B-Instruct (ctx 131072) + ("Llama-3.1-8B-Instruct", "Llama-3.1-8B-Instruct (Q4_K_M)", 4.9, 32, 4096, 8, 128, 32, 131072, "Q4_K_M", "Meta Llama 3.1 8B Instruct, Q4_K_M 量化", 7), + ("Llama-3.1-8B-Instruct", "Llama-3.1-8B-Instruct (Q8_0)", 8.5, 32, 4096, 8, 128, 32, 131072, "Q8_0", "Meta Llama 3.1 8B Instruct, Q8_0 量化", 8), + # Llama-3.1-70B-Instruct (ctx 131072) + ("Llama-3.1-70B-Instruct", "Llama-3.1-70B-Instruct (Q4_K_M)", 38.5, 80, 8192, 8, 128, 64, 131072, "Q4_K_M", "Meta Llama 3.1 70B Instruct, Q4_K_M 量化", 9), + ("Llama-3.1-70B-Instruct", "Llama-3.1-70B-Instruct (Q8_0)", 74.0, 80, 8192, 8, 128, 64, 131072, "Q8_0", "Meta Llama 3.1 70B Instruct, Q8_0 量化", 10), + # Llama-3.1-405B-Instruct (ctx 131072) + ("Llama-3.1-405B-Instruct", "Llama-3.1-405B-Instruct (Q4_K_M)", 226.0, 126, 16384, 8, 128, 128, 131072, "Q4_K_M", "Meta Llama 3.1 405B Instruct, Q4_K_M 量化", 11), + # Qwen2.5-7B-Instruct (ctx 32768) + ("Qwen2.5-7B-Instruct", "Qwen2.5-7B-Instruct (Q4_K_M)", 4.7, 28, 3584, 4, 128, 28, 32768, "Q4_K_M", "Qwen2.5 7B Instruct, Q4_K_M 量化", 12), + ("Qwen2.5-7B-Instruct", "Qwen2.5-7B-Instruct (Q8_0)", 7.6, 28, 3584, 4, 128, 28, 32768, "Q8_0", "Qwen2.5 7B Instruct, Q8_0 量化", 13), + # Qwen2.5-14B-Instruct (ctx 32768) + ("Qwen2.5-14B-Instruct", "Qwen2.5-14B-Instruct (Q4_K_M)", 8.7, 40, 5120, 8, 128, 40, 32768, "Q4_K_M", "Qwen2.5 14B Instruct, Q4_K_M 量化", 14), + # Qwen2.5-32B-Instruct (ctx 32768) + ("Qwen2.5-32B-Instruct", "Qwen2.5-32B-Instruct (Q4_K_M)", 19.5, 64, 5120, 8, 128, 64, 32768, "Q4_K_M", "Qwen2.5 32B Instruct, Q4_K_M 量化", 15), + ("Qwen2.5-32B-Instruct", "Qwen2.5-32B-Instruct (Q8_0)", 32.0, 64, 5120, 8, 128, 64, 32768, "Q8_0", "Qwen2.5 32B Instruct, Q8_0 量化", 16), + # Qwen2.5-72B-Instruct (ctx 32768) + ("Qwen2.5-72B-Instruct", "Qwen2.5-72B-Instruct (Q4_K_M)", 42.0, 80, 8192, 8, 128, 64, 32768, "Q4_K_M", "Qwen2.5 72B Instruct, Q4_K_M 量化", 17), + ("Qwen2.5-72B-Instruct", "Qwen2.5-72B-Instruct (Q8_0)", 75.0, 80, 8192, 8, 128, 64, 32768, "Q8_0", "Qwen2.5 72B Instruct, Q8_0 量化", 18), + # DeepSeek-V2-Chat (ctx 4096) + ("DeepSeek-V2-Chat", "DeepSeek-V2-Chat (Q4_K_M)", 23.0, 60, 5120, 8, 128, 60, 4096, "Q4_K_M", "DeepSeek V2 Chat, Q4_K_M 量化", 19), + # DeepSeek-V2.5-Chat (ctx 4096) + ("DeepSeek-V2.5-Chat", "DeepSeek-V2.5-Chat (Q4_K_M)", 23.0, 60, 5120, 8, 128, 60, 4096, "Q4_K_M", "DeepSeek V2.5 Chat, Q4_K_M 量化", 20), + # DeepSeek-R1-Distill-Qwen-32B (ctx 131072) + ("DeepSeek-R1-Distill-Qwen-32B", "DeepSeek-R1-Distill-Qwen-32B (Q4_K_M)", 19.5, 64, 5120, 8, 128, 64, 131072, "Q4_K_M", "DeepSeek R1 Distill Qwen 32B, Q4_K_M 量化", 21), + ("DeepSeek-R1-Distill-Qwen-32B", "DeepSeek-R1-Distill-Qwen-32B (Q8_0)", 32.0, 64, 5120, 8, 128, 64, 131072, "Q8_0", "DeepSeek R1 Distill Qwen 32B, Q8_0 量化", 22), + # DeepSeek-R1-Distill-Llama-70B (ctx 131072) + ("DeepSeek-R1-Distill-Llama-70B", "DeepSeek-R1-Distill-Llama-70B (Q4_K_M)", 42.0, 80, 8192, 8, 128, 64, 131072, "Q4_K_M", "DeepSeek R1 Distill Llama 70B, Q4_K_M 量化", 23), + ("DeepSeek-R1-Distill-Llama-70B", "DeepSeek-R1-Distill-Llama-70B (Q8_0)", 75.0, 80, 8192, 8, 128, 64, 131072, "Q8_0", "DeepSeek R1 Distill Llama 70B, Q8_0 量化", 24), + # Mistral-7B-Instruct-v0.3 (ctx 32768) + ("Mistral-7B-Instruct-v0.3", "Mistral-7B-Instruct-v0.3 (Q4_K_M)", 4.4, 32, 4096, 8, 128, 32, 32768, "Q4_K_M", "Mistral 7B Instruct v0.3, Q4_K_M 量化", 25), + ("Mistral-7B-Instruct-v0.3", "Mistral-7B-Instruct-v0.3 (Q8_0)", 7.5, 32, 4096, 8, 128, 32, 32768, "Q8_0", "Mistral 7B Instruct v0.3, Q8_0 量化", 26), + # Mixtral-8x7B-Instruct (ctx 32768) + ("Mixtral-8x7B-Instruct", "Mixtral-8x7B-Instruct (Q4_K_M)", 26.0, 32, 4096, 8, 128, 32, 32768, "Q4_K_M", "Mixtral 8x7B Instruct, Q4_K_M 量化", 27), + # Gemma-2-9B-It (ctx 8192) + ("Gemma-2-9B-It", "Gemma-2-9B-It (Q4_K_M)", 5.4, 42, 3584, 4, 256, 14, 8192, "Q4_K_M", "Google Gemma 2 9B It, Q4_K_M 量化", 28), + # Gemma-2-27B-It (ctx 8192) + ("Gemma-2-27B-It", "Gemma-2-27B-It (Q4_K_M)", 16.5, 46, 4608, 4, 128, 36, 8192, "Q4_K_M", "Google Gemma 2 27B It, Q4_K_M 量化", 29), + # Phi-3-Mini-4K-Instruct (ctx 4096) + ("Phi-3-Mini-4K-Instruct", "Phi-3-Mini-4K-Instruct (Q4_K_M)", 2.5, 32, 3072, 32, 96, 32, 4096, "Q4_K_M", "Microsoft Phi-3 Mini 4K Instruct, Q4_K_M 量化", 30), + # Phi-3-Medium-14B-Instruct (ctx 14336) + ("Phi-3-Medium-14B-Instruct", "Phi-3-Medium-14B-Instruct (Q4_K_M)", 8.4, 40, 5120, 10, 128, 40, 14336, "Q4_K_M", "Microsoft Phi-3 Medium 14B Instruct, Q4_K_M 量化", 31), + # GLM-4-9B-Chat (ctx 131072) + ("GLM-4-9B-Chat", "GLM-4-9B-Chat (Q4_K_M)", 5.5, 40, 4096, 4, 128, 40, 131072, "Q4_K_M", "Zhipu GLM-4 9B Chat, Q4_K_M 量化", 32), + ("GLM-4-9B-Chat", "GLM-4-9B-Chat (Q8_0)", 9.0, 40, 4096, 4, 128, 40, 131072, "Q8_0", "Zhipu GLM-4 9B Chat, Q8_0 量化", 33), ] for m in default_models: - c.execute('''INSERT INTO models (base_model, name, size_gb, layers, embd, kv_heads, head_dim, attention_heads, quant, description, sort_order) - VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)''', m) + c.execute('''INSERT INTO models (base_model, name, size_gb, layers, embd, kv_heads, head_dim, attention_heads, default_ctx, quant, description, sort_order) + VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)''', m) # ===== Default settings ===== c.execute("INSERT OR IGNORE INTO settings (key, value) VALUES (?, ?)", ("admin_password", "admin123")) @@ -385,7 +386,7 @@ def insert_default_data(conn): c.execute("INSERT OR IGNORE INTO settings (key, value) VALUES (?, ?)", ("llm_api_url", "")) c.execute("INSERT OR IGNORE INTO settings (key, value) VALUES (?, ?)", ("llm_api_key", "")) c.execute("INSERT OR IGNORE INTO settings (key, value) VALUES (?, ?)", ("llm_api_model", "")) - c.execute("INSERT OR IGNORE INTO settings (key, value) VALUES (?, ?)", ("llm_system_prompt", "你是一个llama.cpp命令行参数解析助手。用户会用自然语言描述他想运行的模型和参数配置,你需要将其解析为JSON格式的参数。\n\n可用的参数键包括: model, ctx_size, n_gpu_layers, threads, batch_size, temperature, top_k, top_p, flash_attn, port, host, parallel, split_mode, mlock, numa, repeat_penalty, presence_penalty, frequency_penalty, seed, min_p, typical, mirostat, mirostat_lr, mirostat_ent。\n\nGPU型号会通过 _gpu_name 字段返回,GPU数量通过 _gpu_count 返回。\n\n只返回JSON,不要其他文本。")) + c.execute("INSERT OR IGNORE INTO settings (key, value) VALUES (?, ?)", ("nl_default_text", "用自然语言描述你想要的配置,支持多行输入。\n例如:\n用RTX 4090跑Llama-3-70B,上下文8192\n温度0.7,开启flash attention\n端口设为8080")) conn.commit() diff --git a/static/admin.html b/static/admin.html index 486b870..080ae9e 100644 --- a/static/admin.html +++ b/static/admin.html @@ -131,6 +131,7 @@ + @@ -138,7 +139,7 @@ - +
ID基模型名称大小(GB)层数EMBDKVHDHeads量化排序操作
ID基模型名称大小层数EMBDKVHDHeads默认CTX量化排序操作
diff --git a/static/css/style.css b/static/css/style.css index 01f990b..814c446 100644 --- a/static/css/style.css +++ b/static/css/style.css @@ -340,6 +340,8 @@ header h1 { .param-tabs { display: flex; gap: 4px; margin-bottom: 12px; flex-wrap: wrap; } .tab-btn { padding: 6px 14px; background: var(--bg-input); border: 1px solid var(--border); color: var(--text-dim); border-radius: var(--radius); cursor: pointer; font-size: 0.85em; } .tab-btn.active { background: var(--accent); color: white; border-color: var(--accent); } +.tab-btn.tab-modified { border-color: var(--accent2); color: var(--accent2); margin-left: auto; } +.tab-btn.tab-modified.active { background: var(--accent2); color: var(--bg); border-color: var(--accent2); } /* ===== Param Search ===== */ .param-search-container { margin-bottom: 12px; position: relative; } @@ -437,11 +439,12 @@ header h1 { /* ===== Command Output ===== */ .command-panel { position: sticky; bottom: 20px; } -.command-output { position: relative; background: #0d1117; border: 1px solid var(--border); border-radius: var(--radius); padding: 16px; font-family: 'Cascadia Code', 'Fira Code', monospace; font-size: 0.9em; color: #4ecca3; word-break: break-all; min-height: 60px; white-space: pre-wrap; } +.command-output-wrap { position: relative; } +.command-output { position: relative; background: #0d1117; border: 1px solid var(--border); border-radius: var(--radius); padding: 16px 16px 16px 70px; font-family: 'Cascadia Code', 'Fira Code', monospace; font-size: 0.9em; color: #4ecca3; word-break: break-all; min-height: 60px; white-space: pre-wrap; } .command-copy-btn { position: absolute; - bottom: 6px; - right: 6px; + top: 6px; + left: 6px; background: var(--bg-input); border: 1px solid var(--border); color: var(--text-dim); @@ -451,6 +454,7 @@ header h1 { font-size: 0.75em; transition: all 0.15s; opacity: 0.7; + z-index: 5; } .command-copy-btn:hover { opacity: 1; border-color: var(--accent2); color: var(--accent2); } .command-copy-btn.copied { background: var(--accent2); color: var(--bg); border-color: var(--accent2); opacity: 1; } diff --git a/static/index.html b/static/index.html index f89b816..854e954 100644 --- a/static/index.html +++ b/static/index.html @@ -90,7 +90,7 @@
- +
@@ -105,7 +105,7 @@

💬 自然语言生成

- +
@@ -126,6 +126,7 @@ +
@@ -135,8 +136,8 @@

📋 生成命令

-
请在上方配置参数...
+
请在上方配置参数...
diff --git a/static/js/admin.js b/static/js/admin.js index 50933ae..a7ea547 100644 --- a/static/js/admin.js +++ b/static/js/admin.js @@ -241,14 +241,15 @@ function renderModelTable() { ${m.id} - - - - - - - - + + + + + + + + + `).join(''); } @@ -263,22 +264,23 @@ async function addModel() { kv_heads: parseInt(document.getElementById('model-kv').value) || 0, head_dim: parseInt(document.getElementById('model-hdim').value) || 0, attention_heads: parseInt(document.getElementById('model-heads').value) || 0, + default_ctx: parseInt(document.getElementById('model-ctx').value) || 0, quant: document.getElementById('model-quant').value, description: document.getElementById('model-desc').value, sort_order: parseInt(document.getElementById('model-order').value) || 0, }; if (!data.base_model || !data.name || !data.size_gb || !data.layers) { alert('请填写基模型、名称、大小和层数'); return; } await fetch('/api/admin/models', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(data) }); - ['model-basemodel','model-name','model-size','model-layers','model-embd','model-kv','model-hdim','model-heads','model-quant','model-desc','model-order'].forEach(id => document.getElementById(id).value = id === 'model-order' ? '0' : ''); + ['model-basemodel','model-name','model-size','model-layers','model-embd','model-kv','model-hdim','model-heads','model-ctx','model-quant','model-desc','model-order'].forEach(id => document.getElementById(id).value = id === 'model-order' ? '0' : ''); await loadAdminModels(); } async function updateModel(id, field, value) { const m = adminState.models.find(m => m.id === id); if (!m) return; - const data = { base_model: m.base_model, name: m.name, size_gb: m.size_gb, layers: m.layers, embd: m.embd, kv_heads: m.kv_heads, head_dim: m.head_dim, attention_heads: m.attention_heads, quant: m.quant, description: m.description, sort_order: m.sort_order }; + const data = { base_model: m.base_model, name: m.name, size_gb: m.size_gb, layers: m.layers, embd: m.embd, kv_heads: m.kv_heads, head_dim: m.head_dim, attention_heads: m.attention_heads, default_ctx: m.default_ctx || 0, quant: m.quant, description: m.description, sort_order: m.sort_order }; if (['size_gb'].includes(field)) data[field] = parseFloat(value) || 0; - else if (['layers','embd','kv_heads','head_dim','attention_heads','sort_order'].includes(field)) data[field] = parseInt(value) || 0; + else if (['layers','embd','kv_heads','head_dim','attention_heads','default_ctx','sort_order'].includes(field)) data[field] = parseInt(value) || 0; else data[field] = value; await fetch(`/api/admin/models/${id}`, { method: 'PUT', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(data) }); await loadAdminModels(); @@ -305,6 +307,7 @@ function renderSettings() { 'default_version': '默认版本', 'default_mode': '默认模式', 'default_quant': '默认量化版本', + 'nl_default_text': '自然语言默认提示文本', 'llm_enabled': '启用LLM解析 (true/false)', 'llm_api_url': 'LLM API URL', 'llm_api_key': 'LLM API Key', diff --git a/static/js/main.js b/static/js/main.js index 7dff62c..4558f86 100644 --- a/static/js/main.js +++ b/static/js/main.js @@ -14,6 +14,7 @@ async function init() { await loadVersions(); await loadGpus(); await loadModelsGrouped(); + await loadNlDefaultText(); const dv = state.versions.find(v => v.version_tag === 'b10068') || state.versions[0]; if (dv) { state.currentVersionId = dv.id; document.getElementById('version-select').value = dv.id; await loadParams(dv.id); } const dg = state.gpus.find(g => g.name === 'RTX 3090') || state.gpus[0]; @@ -21,6 +22,15 @@ async function init() { renderParams(); generateCommand(); updateEstimate(); } +async function loadNlDefaultText() { + const res = await fetch('/api/settings/public'); + const data = await res.json(); + const ta = document.getElementById('nl-input'); + if (data.nl_default_text) { + ta.placeholder = data.nl_default_text; + } +} + // ===== Load Data ===== async function loadVersions() { const res = await fetch('/api/versions'); state.versions = await res.json(); @@ -76,10 +86,26 @@ function updateGpuSlot(i, name) { const g = state.gpus.find(g => g.name === name // ===== Model Selection ===== function filterBaseModels() { const text = document.getElementById('model-search').value.toLowerCase(); - state.filteredBaseModels = state.baseModelList.filter(n => n.toLowerCase().includes(text)); + if (!text) { + // Show top 5 when input is empty (on focus) + state.filteredBaseModels = state.baseModelList.slice(0, 5); + } else { + state.filteredBaseModels = state.baseModelList.filter(n => n.toLowerCase().includes(text)); + } renderBaseModelDropdown(); document.getElementById('model-dropdown').style.display = state.filteredBaseModels.length > 0 ? 'block' : 'none'; } +function onModelSearchFocus() { + if (!document.getElementById('model-search').value) { + state.filteredBaseModels = state.baseModelList.slice(0, 5); + renderBaseModelDropdown(); + document.getElementById('model-dropdown').style.display = 'block'; + } +} +function onModelSearchBlur() { + // Delay to allow click on option + setTimeout(() => { document.getElementById('model-dropdown').style.display = 'none'; }, 200); +} function renderBaseModelDropdown() { document.getElementById('model-dropdown').innerHTML = state.filteredBaseModels.map(n => { const quants = state.modelsGrouped[n] || []; @@ -117,9 +143,25 @@ function selectModel(id) { Head Dim: ${m.head_dim} 量化: ${m.quant || 'N/A'} `; + // Auto-adjust params based on selected model + applyModelDefaults(m); updateEstimate(); } +function applyModelDefaults(m) { + // Set ctx_size to model's default context if available + if (m.default_ctx && m.default_ctx > 0) { + state.paramValues['ctx_size'] = String(m.default_ctx); + } + // Set n_gpu_layers to 'all' for GPU mode + if (state.mode === 'gpu') { + state.paramValues['n_gpu_layers'] = 'all'; + } + // Update param UI if currently visible + renderParams(); + generateCommand(); +} + // ===== Parameter Rendering ===== function switchTab(cat) { state.currentTab = cat; @@ -151,6 +193,10 @@ function onParamSearch() { } function getFilteredParams() { + // 'modified' is a special tab showing all modified params + if (state.currentTab === 'modified') { + return state.params.filter(p => isParamModified(p, state.paramValues[p.param_key])); + } let params = state.params.filter(p => p.category === state.currentTab); if (state.paramSearchText) { params = state.params.filter(p => @@ -166,7 +212,8 @@ function getFilteredParams() { function renderParams() { const container = document.getElementById('param-container'); const all = getFilteredParams(); - if (state.paramSearchText) { + // For 'modified' tab, show all (no important/hidden distinction) + if (state.currentTab === 'modified' || state.paramSearchText) { container.innerHTML = all.map(p => renderParamItem(p)).join(''); document.getElementById('toggle-advanced-btn').style.display = 'none'; return; @@ -220,7 +267,8 @@ function isParamModified(p, val) { function setParam(key, value) { state.paramValues[key] = value; - // No visual modification marker per user request + // If on 'modified' tab, re-render to update the list + if (state.currentTab === 'modified') renderParams(); generateCommand(); updateEstimate(); }