feat: DTC-коды: справочник, эндпоинты /dtc/decode, /dtc/upload
This commit is contained in:
@@ -231,6 +231,30 @@ class Database:
|
||||
).fetchall()
|
||||
return [dict(r) for r in rows]
|
||||
|
||||
def save_dtc_scan(self, client_info: dict, dtc_codes: list[str]):
|
||||
"""Сохраняет быстрый скан кодов ошибок."""
|
||||
self.conn.execute("""
|
||||
INSERT INTO sessions (
|
||||
client_ip, real_ip, user_agent,
|
||||
phone_model, phone_maker, android_version, android_sdk,
|
||||
app_version, android_id, device_uuid,
|
||||
elm_mac, elm_bt_name,
|
||||
dtc_count, response_count,
|
||||
script_mode, transport,
|
||||
raw_responses
|
||||
) VALUES (?,?,?, ?,?,?,?, ?,?,?, ?,?, ?,?, ?,?,?)
|
||||
""", (
|
||||
client_info.get("client_ip"), client_info.get("real_ip"), client_info.get("user_agent"),
|
||||
client_info.get("phone_model"), client_info.get("phone_maker"), client_info.get("android_version"),
|
||||
client_info.get("android_sdk"), client_info.get("app_version"), client_info.get("android_id"),
|
||||
client_info.get("device_uuid"),
|
||||
client_info.get("elm_mac"), client_info.get("elm_bt_name"),
|
||||
len(dtc_codes), 0,
|
||||
"dtc_scan", client_info.get("transport", "bt"),
|
||||
json.dumps([{"decoded": f"DTC stored: {c}"} for c in dtc_codes], ensure_ascii=False)
|
||||
))
|
||||
self.conn.commit()
|
||||
|
||||
# ── cars ──────────────────────────────────────────────
|
||||
|
||||
def get_or_create_car(self, vin: str) -> int:
|
||||
|
||||
@@ -6,6 +6,7 @@ POST /api/v1/session/upload — приём батча, LLM-анализ, воз
|
||||
|
||||
import logging
|
||||
import time
|
||||
from pathlib import Path
|
||||
|
||||
from flask import jsonify, request
|
||||
|
||||
@@ -63,6 +64,23 @@ def _build_diagnosis_prompt(data: dict, car_info: str = "") -> str:
|
||||
return "\n".join(parts)
|
||||
|
||||
|
||||
# Загрузка справочника DTC
|
||||
_DTC_CODES: dict[str, str] = {}
|
||||
|
||||
def _load_dtc_dict():
|
||||
global _DTC_CODES
|
||||
if _DTC_CODES:
|
||||
return _DTC_CODES
|
||||
path = Path(__file__).parent.parent / "doc" / "dtc_codes.txt"
|
||||
if path.exists():
|
||||
for line in path.read_text(encoding="utf-8").splitlines():
|
||||
line = line.strip()
|
||||
if "=" in line and not line.startswith("#"):
|
||||
code, desc = line.split("=", 1)
|
||||
_DTC_CODES[code.strip()] = desc.strip()
|
||||
return _DTC_CODES
|
||||
|
||||
|
||||
def register(app):
|
||||
"""Регистрирует эндпоинты скриптов на Flask-приложении."""
|
||||
|
||||
@@ -234,6 +252,40 @@ def register(app):
|
||||
_ping_llm_cache = {"ts": now, "data": result, "ttl": ttl}
|
||||
return jsonify(result)
|
||||
|
||||
@app.route("/api/v1/dtc/decode", methods=["POST"])
|
||||
def dtc_decode():
|
||||
"""Расшифровка кодов DTC."""
|
||||
data = request.get_json(silent=True) or {}
|
||||
codes = data.get("codes", [])
|
||||
if not codes:
|
||||
return jsonify({"codes": []})
|
||||
dtc = _load_dtc_dict()
|
||||
decoded = []
|
||||
for c in codes:
|
||||
c = c.strip().upper()
|
||||
decoded.append({"code": c, "desc": dtc.get(c, c)})
|
||||
return jsonify({"codes": decoded})
|
||||
|
||||
@app.route("/api/v1/dtc/upload", methods=["POST"])
|
||||
def dtc_upload():
|
||||
"""Приём кодов ошибок без полной диагностики."""
|
||||
data = request.get_json(silent=True)
|
||||
if not data:
|
||||
return jsonify({"error": "empty"}), 400
|
||||
codes = data.get("dtc_codes", [])
|
||||
client_info = data.get("client_info", {})
|
||||
client_info["client_ip"] = request.remote_addr
|
||||
|
||||
try:
|
||||
with Database() as db:
|
||||
db.save_dtc_scan(client_info, codes)
|
||||
except Exception as e:
|
||||
logger.error(f"DTC upload failed: {e}")
|
||||
|
||||
dtc = _load_dtc_dict()
|
||||
decoded = [{"code": c, "desc": dtc.get(c.strip().upper(), c)} for c in codes]
|
||||
return jsonify({"codes": decoded, "count": len(decoded)})
|
||||
|
||||
|
||||
def _summary(p: dict) -> dict:
|
||||
return {
|
||||
|
||||
Reference in New Issue
Block a user