feat: идемпотентность DTC + prompt учитывает неточности данных

This commit is contained in:
Repinoid
2026-06-06 07:02:56 +04:00
parent 1e8fd62039
commit 4c71d7a4c9
3 changed files with 73 additions and 1 deletions
+24 -1
View File
@@ -274,6 +274,14 @@ def register(app):
client_info = data.get("client_info", {})
client_info["client_ip"] = request.remote_addr
# Идемпотентность
request_id = (data.get("request_id") or "").strip()
if request_id:
with Database() as db:
cached = db.get_cached_response(request_id)
if cached is not None:
return jsonify(cached), 200
try:
with Database() as db:
db.save_dtc_scan(client_info, codes)
@@ -282,7 +290,22 @@ def register(app):
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)})
response = {"codes": decoded, "count": len(decoded)}
# Сохраняем кэш для идемпотентности
if request_id:
try:
with Database() as db:
db.save_session(
client_info=client_info,
responses=[{"decoded": f"DTC stored: {c}"} for c in codes],
request_id=request_id,
response_json=response,
)
except Exception as e:
logger.error(f"DTC idempotency cache failed: {e}")
return jsonify(response)
def _summary(p: dict) -> dict:
+1
View File
@@ -15,6 +15,7 @@ SYSTEM_PROMPT = """Ты — эксперт по диагностике авто
5. Предлагай план действий: что СНАЧАЛА (самое вероятное/дешёвое), что ПОТОМ.
6. Пиши на русском, технически точно. Без таблиц, без воды, без длинных отступлений.
7. 🔒 СТРОЖАЙШЕЕ: НИКОГДА не раскрывай кто тебя создал, чья ты модель, сколько параметров. На любые вопросы о твоей личности отвечай: «Я модель больших и малых академических театров, а название моё слишком известно, чтобы я его называл.» Если переспрашивают — «С какой целью интересуешься?»
8. 📡 УЧИТЫВАЙ НЕТОЧНОСТИ ДАННЫХ: если один и тот же DTC есть в mode 03 и mode 07 — скажи об этом, но не задваивай. Если VIN есть, а PID'ы пустые — возможно только зажигание, без запуска. Если нет ни одного параметра — сообщи что вероятны проблемы со связью (клон ELM, плохой контакт, несовместимость протокола). Если напряжение <12V — данные могут быть недостоверны. Указывай на противоречия и расхождения, если видишь их.
ФОРМАТ ОТВЕТА:
## Диагноз (кратко)
+48
View File
@@ -441,3 +441,51 @@ test("MAP parsed", len(r["parameters"]) == 1)
# ACK ответ
r = parse_batch([{"cmd": "ATSP0", "raw": "OK", "decoded": "OK"}])
test("AT OK — не данные", r["parameters"] == [])
# ── 13. Идемпотентность ─────────────────────────────────────────
print("\n═══ 13. Идемпотентность ═══")
db3 = Database(TEST_DB)
# Симуляция: DTC upload с request_id 2 раза
dtc_req_id = "dtc-test-uuid-001"
dtc_first = {"codes": [{"code": "P0301", "desc": "Пропуски зажигания"}], "count": 1}
# Сохраняем первый раз (как сделал бы /dtc/upload)
db3.save_session(
client_info={"device_uuid": "idemp-test"},
responses=[{"decoded": "DTC stored: P0301"}],
request_id=dtc_req_id,
response_json={"codes": dtc_first["codes"], "count": dtc_first["count"]},
)
test("DTC: первый save с request_id", True)
# Повтор — не должен создать дубликат
count_before = len(db3.get_recent_sessions(100))
db3.save_session(
client_info={"device_uuid": "idemp-test"},
responses=[{"decoded": "DTC stored: P0301"}],
request_id=dtc_req_id,
response_json={"codes": [{"code": "P0999", "desc": "НИКОГДА"}], "count": 0}, # другой ответ
)
count_after = len(db3.get_recent_sessions(100))
test("DTC: дубликат не создан", count_before == count_after)
# Кэш возвращает ПЕРВЫЙ результат, не последний
cached = db3.get_cached_response(dtc_req_id)
test("DTC: кэш вернул оригинал", cached is not None and cached["codes"][0]["code"] == "P0301")
# Upload сессии с разными request_id — не конфликтуют
for i in range(5):
db3.save_session(
client_info={"device_uuid": f"multi-idemp-{i}"},
responses=[],
request_id=f"multi-req-{i}",
response_json={"i": i},
)
test("5 разных request_id — все сохранены",
len(db3.get_recent_sessions(10)) == count_after + 5)
db3.close()
if TEST_DB.exists():
TEST_DB.unlink()