refactor: архитектура сервера — obd/ brain/ api/
- obd/protocol.py — ELM327 стейт-машина AndrOBD (подробные докстринги) - brain/client.py — LLM-клиент Diagnoser - brain/prompts.py — системные промпты - api/db.py — SQLite (sessions + старые таблицы) - api/scripts.py — сборка диагностических скриптов - api/parser.py — парсинг ответов ELM327 - api/routes.py — все REST-эндпоинты - api/config.py — загрузка конфига - web/app.py — точка входа Flask (упрощена) Удалено: elmer/elm.py, elmer/elm_proto.py, web/raw_endpoint.py
This commit is contained in:
+13
-76
@@ -1,33 +1,31 @@
|
||||
"""Elmer Web UI — Flask-приложение для локального тестирования.
|
||||
"""elmAI — точка входа Flask-приложения.
|
||||
|
||||
Заодно прототип будущего серверного API.
|
||||
Запуск: DEEPSEEK_API_KEY=sk-... python web/app.py
|
||||
Открыть: http://localhost:5005
|
||||
Запуск через gunicorn:
|
||||
gunicorn -w 4 -b 127.0.0.1:8000 web.app:app
|
||||
|
||||
Структура модулей:
|
||||
api/ — REST-эндпоинты, БД, скрипты
|
||||
brain/ — LLM-клиент, промпты
|
||||
obd/ — ELM327-протокол (AndrOBD)
|
||||
"""
|
||||
|
||||
import sys
|
||||
import logging
|
||||
from pathlib import Path
|
||||
|
||||
# Добавляем корень проекта в PYTHONPATH
|
||||
# Добавляем корень проекта в PYTHONPATH для импорта api/, brain/, obd/
|
||||
sys.path.insert(0, str(Path(__file__).parent.parent))
|
||||
|
||||
from flask import Flask, jsonify, redirect, render_template, request, send_from_directory
|
||||
|
||||
from elmer.config import load
|
||||
from elmer.db import Database
|
||||
from elmer.diagnose import Diagnoser
|
||||
from elmer.elm import ELM327
|
||||
from elmer.prompts import SYSTEM_PROMPT, build_user_prompt
|
||||
from web.raw_endpoint import register as register_raw_endpoint
|
||||
from web.script_endpoint import register as register_script_endpoint
|
||||
from api.config import load
|
||||
from api.routes import register as register_api
|
||||
|
||||
logging.basicConfig(level=logging.INFO, format="%(asctime)s [%(name)s] %(message)s")
|
||||
|
||||
app = Flask(__name__)
|
||||
config = load()
|
||||
register_raw_endpoint(app)
|
||||
register_script_endpoint(app)
|
||||
register_api(app)
|
||||
|
||||
|
||||
@app.route("/")
|
||||
@@ -42,67 +40,6 @@ def download_apk():
|
||||
return send_from_directory("static", "app-debug.apk", as_attachment=True, download_name="elmer.apk")
|
||||
|
||||
|
||||
@app.route("/api/diagnose", methods=["POST"])
|
||||
def diagnose():
|
||||
"""Подключается к ELM327, читает данные, отправляет в LLM, возвращает результат."""
|
||||
elm_cfg = config["elm327"]
|
||||
|
||||
# ── 1. ELM327 ────────────────────────────────
|
||||
try:
|
||||
elm = ELM327(port=elm_cfg["port"], baudrate=elm_cfg["baudrate"])
|
||||
except Exception as e:
|
||||
return jsonify({"error": f"Не удалось открыть порт {elm_cfg['port']}: {e}"}), 500
|
||||
|
||||
if not elm.init():
|
||||
elm.close()
|
||||
return jsonify({"error": "ELM327 не ответил на ATZ"}), 500
|
||||
|
||||
# ── 2. VIN ──────────────────────────────────
|
||||
vin = elm.read_vin()
|
||||
if not vin:
|
||||
elm.close()
|
||||
return jsonify({"error": "Не удалось прочитать VIN (режим 09 не поддерживается?)"}), 500
|
||||
|
||||
# ── 3. Ошибки ───────────────────────────────
|
||||
dtc_codes = elm.read_dtc_codes("03") + elm.read_dtc_codes("07")
|
||||
|
||||
# ── 4. Параметры ────────────────────────────
|
||||
parameters = elm.read_all_pids(config.get("pids"))
|
||||
|
||||
elm.close()
|
||||
|
||||
# ── 5. DeepSeek ─────────────────────────────
|
||||
api_key = config["deepseek"]["api_key"]
|
||||
if not api_key:
|
||||
return jsonify({"error": "DEEPSEEK_API_KEY не задан"}), 500
|
||||
|
||||
diagnoser = Diagnoser(
|
||||
api_key=api_key,
|
||||
model=config["deepseek"].get("model", "deepseek-chat"),
|
||||
)
|
||||
user_prompt = build_user_prompt(vin, dtc_codes, parameters)
|
||||
answer = diagnoser.diagnose(SYSTEM_PROMPT, user_prompt)
|
||||
|
||||
# ── 6. SQLite ───────────────────────────────
|
||||
db = Database()
|
||||
car_id = db.get_or_create_car(vin)
|
||||
token_id = db.create_token(car_id)
|
||||
for dtc in dtc_codes:
|
||||
db.add_dtc(token_id, dtc["code"], dtc.get("description", ""), dtc["status"])
|
||||
for p in parameters:
|
||||
db.add_parameter(token_id, p["pid_code"], p["name"], p["value"], p["unit"])
|
||||
db.add_llm_message(token_id, "user", user_prompt)
|
||||
db.add_llm_message(token_id, "assistant", answer)
|
||||
|
||||
return jsonify({
|
||||
"vin": vin,
|
||||
"dtc_codes": dtc_codes,
|
||||
"parameters": parameters,
|
||||
"diagnosis": answer,
|
||||
"token_id": token_id,
|
||||
})
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
print(f"🌐 Elmer Web: http://localhost:5005")
|
||||
print(f"🌐 elmAI Web: http://localhost:5005")
|
||||
app.run(host="0.0.0.0", port=5005, debug=False)
|
||||
|
||||
Reference in New Issue
Block a user