fix(server): X-Api-Key проверка на upload/chat/ping-llm, лимит 2000 ответов
This commit is contained in:
+5
-2
@@ -28,8 +28,11 @@ def register(app):
|
|||||||
|
|
||||||
@app.route("/api/v1/ping-llm", methods=["GET"])
|
@app.route("/api/v1/ping-llm", methods=["GET"])
|
||||||
def ping_llm():
|
def ping_llm():
|
||||||
"""Проверка LLM с адаптивным кэшем.
|
"""Проверка LLM с адаптивным кэшем. # API key check
|
||||||
|
cfg = load()
|
||||||
|
required = cfg.get("api", {}).get("key", "")
|
||||||
|
if required and request.headers.get("X-Api-Key", "") != required:
|
||||||
|
return jsonify({"ok": False, "error": "unauthorized"}), 401
|
||||||
- Успех → кэш 60с
|
- Успех → кэш 60с
|
||||||
- Ошибка → кэш 7с (LLM мог уже ожить)
|
- Ошибка → кэш 7с (LLM мог уже ожить)
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -23,6 +23,20 @@ from brain.prompts import SYSTEM_PROMPT, DYNAMIC_PROMPT
|
|||||||
logger = logging.getLogger("elmer.script")
|
logger = logging.getLogger("elmer.script")
|
||||||
|
|
||||||
|
|
||||||
|
def _check_api_key():
|
||||||
|
"""Проверяет X-Api-Key. Если в конфиге нет ключа — пропускаем (dev-режим)."""
|
||||||
|
cfg = load()
|
||||||
|
required = cfg.get("api", {}).get("key", "")
|
||||||
|
if not required:
|
||||||
|
return True # dev-режим, без ключа
|
||||||
|
provided = request.headers.get("X-Api-Key", "")
|
||||||
|
return provided == required
|
||||||
|
|
||||||
|
|
||||||
|
def _auth_error():
|
||||||
|
return jsonify({"error": "unauthorized", "hint": "передайте X-Api-Key"}), 401
|
||||||
|
|
||||||
|
|
||||||
def _build_diagnosis_prompt(data: dict, car_info: str = "") -> str:
|
def _build_diagnosis_prompt(data: dict, car_info: str = "") -> str:
|
||||||
"""Строит промпт для LLM из распарсенных данных."""
|
"""Строит промпт для LLM из распарсенных данных."""
|
||||||
parts = ["## Данные диагностики\n"]
|
parts = ["## Данные диагностики\n"]
|
||||||
@@ -87,11 +101,15 @@ def register(app):
|
|||||||
|
|
||||||
@app.route("/api/v1/session/upload", methods=["POST"])
|
@app.route("/api/v1/session/upload", methods=["POST"])
|
||||||
def upload_session():
|
def upload_session():
|
||||||
|
if not _check_api_key():
|
||||||
|
return _auth_error()
|
||||||
data = request.get_json(silent=True)
|
data = request.get_json(silent=True)
|
||||||
if not data or "responses" not in data:
|
if not data or "responses" not in data:
|
||||||
return jsonify({"error": "missing 'responses'"}), 400
|
return jsonify({"error": "missing 'responses'"}), 400
|
||||||
|
|
||||||
responses = data["responses"]
|
responses = data["responses"]
|
||||||
|
if len(responses) > 2000:
|
||||||
|
return jsonify({"error": "too many responses (max 2000)"}), 400
|
||||||
|
|
||||||
# Динамический тест: если есть — добавляем к обычным ответам
|
# Динамический тест: если есть — добавляем к обычным ответам
|
||||||
dynamic_samples = data.get("dynamic_samples")
|
dynamic_samples = data.get("dynamic_samples")
|
||||||
@@ -181,6 +199,8 @@ def register(app):
|
|||||||
|
|
||||||
@app.route("/api/v1/chat", methods=["POST"])
|
@app.route("/api/v1/chat", methods=["POST"])
|
||||||
def chat():
|
def chat():
|
||||||
|
if not _check_api_key():
|
||||||
|
return _auth_error()
|
||||||
"""Свободный вопрос к LLM (без ELM)."""
|
"""Свободный вопрос к LLM (без ELM)."""
|
||||||
data = request.get_json(silent=True)
|
data = request.get_json(silent=True)
|
||||||
if not data or "question" not in data:
|
if not data or "question" not in data:
|
||||||
@@ -245,6 +265,8 @@ def register(app):
|
|||||||
|
|
||||||
mac = data["mac"].strip()
|
mac = data["mac"].strip()
|
||||||
responses = data["responses"]
|
responses = data["responses"]
|
||||||
|
if len(responses) > 2000:
|
||||||
|
return jsonify({"error": "too many responses (max 2000)"}), 400
|
||||||
|
|
||||||
if not mac:
|
if not mac:
|
||||||
return jsonify({"error": "empty mac"}), 400
|
return jsonify({"error": "empty mac"}), 400
|
||||||
|
|||||||
Reference in New Issue
Block a user