átlagos kiegészítséek jó sok
This commit is contained in:
186
backend/app/admin_ui.py
Normal file
186
backend/app/admin_ui.py
Normal file
@@ -0,0 +1,186 @@
|
||||
#!/usr/bin/env python3
|
||||
import asyncio
|
||||
import json
|
||||
import urllib.parse
|
||||
import streamlit as st
|
||||
from sqlalchemy import text
|
||||
from app.database import AsyncSessionLocal
|
||||
|
||||
# Streamlit oldal alapbeállításai
|
||||
st.set_page_config(
|
||||
page_title="Service Finder - HITL Adattisztító",
|
||||
page_icon="🔧",
|
||||
layout="wide"
|
||||
)
|
||||
|
||||
# --- ADATBÁZIS MŰVELETEK (Hardened Stateless Logic) ---
|
||||
|
||||
async def get_review_vehicle():
|
||||
"""Lekérdez egy javításra váró járművet izolált sessionben."""
|
||||
async with AsyncSessionLocal() as session:
|
||||
try:
|
||||
query = text("""
|
||||
SELECT id, make, marketing_name, year_from, fuel_type,
|
||||
raw_api_data, raw_search_context,
|
||||
trim_level, body_type, power_kw, engine_capacity,
|
||||
specifications, last_error
|
||||
FROM vehicle.vehicle_model_definitions
|
||||
WHERE status = 'manual_review_needed'
|
||||
ORDER BY priority_score DESC
|
||||
LIMIT 1
|
||||
""")
|
||||
result = await session.execute(query)
|
||||
row = result.fetchone()
|
||||
if not row:
|
||||
return None
|
||||
|
||||
vehicle = dict(row._mapping)
|
||||
|
||||
# URL bányászat a JSON adatokból
|
||||
source_url = None
|
||||
if vehicle.get('raw_api_data'):
|
||||
api_data = vehicle['raw_api_data']
|
||||
if isinstance(api_data, str):
|
||||
try: api_data = json.loads(api_data)
|
||||
except: api_data = {}
|
||||
source_url = api_data.get('url') or api_data.get('source_url') or api_data.get('link')
|
||||
|
||||
vehicle['extracted_url'] = source_url
|
||||
return vehicle
|
||||
except Exception as e:
|
||||
st.error(f"❌ Lekérdezési hiba: {e}")
|
||||
return None
|
||||
finally:
|
||||
# Garantáljuk a session lezárását
|
||||
await session.close()
|
||||
|
||||
async def update_vehicle_data(vehicle_id, updates, new_status):
|
||||
"""Elmenti az adatokat és azonnal felszabadítja a hálózati erőforrásokat."""
|
||||
session = AsyncSessionLocal()
|
||||
try:
|
||||
# Dinamikus SQL összeállítása
|
||||
set_items = [f"{k} = :{k}" for k in updates.keys()]
|
||||
set_clause = ", ".join(set_items)
|
||||
|
||||
sql = text(f"""
|
||||
UPDATE vehicle.vehicle_model_definitions
|
||||
SET status = :status, {set_clause}, updated_at = NOW()
|
||||
WHERE id = :id
|
||||
""")
|
||||
|
||||
params = {"status": new_status, "id": vehicle_id, **updates}
|
||||
|
||||
await session.execute(sql, params)
|
||||
await session.commit()
|
||||
return True
|
||||
except Exception as e:
|
||||
await session.rollback()
|
||||
st.error(f"❌ Mentési hiba az adatbázisban: {e}")
|
||||
return False
|
||||
finally:
|
||||
# KRITIKUS JAVÍTÁS: Explicit lezárás, hogy ne maradjon nyitott transport
|
||||
await session.close()
|
||||
# Itt kényszerítjük a kapcsolat-kezelőt a háttérben futó motor elengedésére
|
||||
bind = session.bind
|
||||
if bind:
|
||||
await bind.dispose()
|
||||
|
||||
# --- UI LOGIKA ---
|
||||
|
||||
async def main_async():
|
||||
st.title("🔧 HITL Adattisztító - Autó Adat Javítás")
|
||||
|
||||
# Adat betöltése a memóriába (ha üres)
|
||||
if "current_vehicle" not in st.session_state or st.session_state.current_vehicle is None:
|
||||
with st.spinner("Adatbázis szinkronizálása..."):
|
||||
st.session_state.current_vehicle = await get_review_vehicle()
|
||||
|
||||
v = st.session_state.current_vehicle
|
||||
|
||||
if not v:
|
||||
st.success("🎉 Minden jármű ellenőrizve!")
|
||||
if st.button("🔄 Új lekérdezés"):
|
||||
st.session_state.current_vehicle = None
|
||||
st.rerun()
|
||||
return
|
||||
|
||||
# Felület felépítése
|
||||
st.header(f"🚗 {v['year_from'] or '????'} {v['make']} {v['marketing_name']}")
|
||||
st.caption(f"DB ID: {v['id']} | Üzemanyag: {v['fuel_type'] or 'n/a'}")
|
||||
|
||||
# 3 oszlopos nézet
|
||||
col_raw, col_source, col_edit = st.columns([1, 1, 1.2])
|
||||
|
||||
with col_raw:
|
||||
st.subheader("📄 Robot Naplók")
|
||||
if v['raw_api_data']:
|
||||
with st.expander("Nyers JSON (API)", expanded=True):
|
||||
st.json(v['raw_api_data'])
|
||||
with st.expander("Keresési Környezet", expanded=False):
|
||||
st.text_area("Talált szövegek", v['raw_search_context'] or "Nincs adat", height=400)
|
||||
|
||||
with col_source:
|
||||
st.subheader("🔗 Eredeti Források")
|
||||
if v['extracted_url']:
|
||||
st.success("📍 Közvetlen adatlap linkje:")
|
||||
st.markdown(f"### [FORRÁS MEGNYITÁSA ↗️]({v['extracted_url']})")
|
||||
else:
|
||||
st.warning("⚠️ Nincs közvetlen link.")
|
||||
|
||||
st.markdown("---")
|
||||
st.write("**Segédeszközök:**")
|
||||
search_q = urllib.parse.quote(f"{v['make']} {v['marketing_name']} {v['year_from'] or ''} specifications")
|
||||
st.markdown(f"- [🔍 Google Keresés](https://www.google.com/search?q={search_q})")
|
||||
us_query = urllib.parse.quote(f"{v['make']} {v['marketing_name']}")
|
||||
us_url = f"https://www.google.com/search?q=site:ultimatespecs.com+{us_query}"
|
||||
|
||||
if v['specifications']:
|
||||
with st.expander("Már meglévő specifikációk", expanded=True):
|
||||
st.json(v['specifications'])
|
||||
|
||||
with col_edit:
|
||||
st.subheader("✏️ Adatbevitel")
|
||||
with st.form("hitl_form_v2", clear_on_submit=False):
|
||||
trim = st.text_input("Trim / Felszereltség", value=v['trim_level'] or "")
|
||||
|
||||
body_opts = ["", "SEDAN", "HATCHBACK", "SUV", "ESTATE", "COUPE", "CONVERTIBLE", "VAN", "PICKUP", "MPV"]
|
||||
curr_body = v['body_type'] if v['body_type'] in body_opts else ""
|
||||
body = st.selectbox("Karosszéria", body_opts, index=body_opts.index(curr_body))
|
||||
|
||||
pwr = st.number_input("Teljesítmény (kW)", value=int(v['power_kw'] or 0))
|
||||
cap = st.number_input("Hengerűrtartalom (cm³)", value=int(v['engine_capacity'] or 0))
|
||||
|
||||
st.markdown("---")
|
||||
comment = st.text_area("Megjegyzés (második zsák adatai)", placeholder="További kiegészítő adatok...")
|
||||
|
||||
st.write("")
|
||||
b1, b2, b3 = st.columns(3)
|
||||
save_btn = b1.form_submit_button("💾 MENTÉS", type="primary")
|
||||
skip_btn = b2.form_submit_button("⏭️ KIHAGYÁS")
|
||||
reject_btn = b3.form_submit_button("🗑️ KUKA")
|
||||
|
||||
# Mentési logika
|
||||
if save_btn:
|
||||
updates = {
|
||||
"trim_level": trim,
|
||||
"body_type": body,
|
||||
"power_kw": pwr,
|
||||
"engine_capacity": cap,
|
||||
"last_error": f"Manual fix OK. {comment}".strip()
|
||||
}
|
||||
with st.spinner("Véglegesítés..."):
|
||||
if await update_vehicle_data(v['id'], updates, "published"):
|
||||
st.session_state.current_vehicle = None
|
||||
st.rerun()
|
||||
|
||||
if skip_btn:
|
||||
st.session_state.current_vehicle = None
|
||||
st.rerun()
|
||||
|
||||
if reject_btn:
|
||||
if await update_vehicle_data(v['id'], {"last_error": "Manual rejection"}, "rejected"):
|
||||
st.session_state.current_vehicle = None
|
||||
st.rerun()
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main_async())
|
||||
Reference in New Issue
Block a user