mgokg's picture
Update app.py
0ac6697 verified
import gradio as gr
import requests
from datetime import datetime, timedelta
import xml.etree.ElementTree as ET
import json
import os
# Lade Anmeldeinformationen aus Umgebungsvariablen
CLIENT_ID = os.environ.get('client_id')
API_KEY = os.environ.get('api_key')
def json_to_markdown_table(json_data):
"""
Konvertiert JSON-Daten in eine professionell formatierte Markdown-Tabelle
"""
if isinstance(json_data, str):
data = json.loads(json_data)
else:
data = json_data
if not data:
return "Keine Daten vorhanden"
# Check for error
if isinstance(data, dict) and "error" in data:
return f"**Fehler:** {data['error']}"
header_mapping = {
"startort": "🚉 Startort",
"zielort": "🎯 Zielort",
"abfahrtszeit": "⏰ Abfahrt",
"ankunftszeitszeit": "⏱️ Ankunft",
"gleis": "🛤️ Gleis",
"duration": "⏳ Dauer"
}
columns = list(data[0].keys())
headers = [header_mapping.get(col, col) for col in columns]
markdown = "| " + " | ".join(headers) + " |\n"
markdown += "|" + "|".join(["---" for _ in headers]) + "|\n"
for row in data:
values = [str(row.get(col, "")) for col in columns]
markdown += "| " + " | ".join(values) + " |\n"
return markdown
def get_station_info(pattern, client_id, api_key):
url = f"https://apis.deutschebahn.com/db-api-marketplace/apis/timetables/v1/station/{pattern}"
headers = {'DB-Client-Id': client_id, 'DB-Api-Key': api_key, 'accept': 'application/xml'}
try:
response = requests.get(url, headers=headers, timeout=10)
root = ET.fromstring(response.content)
station = root.find('station')
if station is not None:
return {'name': station.get('name'), 'eva': station.get('eva')}
except Exception:
return None
return None
def fetch_timetable_hour(eva, date_str, hour_str, client_id, api_key):
url = f"https://apis.deutschebahn.com/db-api-marketplace/apis/timetables/v1/plan/{eva}/{date_str}/{hour_str}"
headers = {'DB-Client-Id': client_id, 'DB-Api-Key': api_key, 'accept': 'application/xml'}
try:
response = requests.get(url, headers=headers, timeout=10)
if response.status_code == 200:
return ET.fromstring(response.content)
except Exception:
pass
return None
def search_next_3_connections(departure, destination, client_id, api_key):
if not all([departure, destination, client_id, api_key]):
return {"error": "Bitte alle Felder ausfüllen."}
dep_info = get_station_info(departure, client_id, api_key)
dest_info = get_station_info(destination, client_id, api_key)
if not dep_info: return {"error": f"Startort '{departure}' nicht gefunden."}
if not dest_info: return {"error": f"Zielort '{destination}' nicht gefunden."}
now = datetime.now()
found_connections = []
for hour_offset in range(3):
search_time = now + timedelta(hours=hour_offset)
datum = search_time.strftime("%y%m%d")
stunde = search_time.strftime("%H")
root = fetch_timetable_hour(dep_info['eva'], datum, stunde, client_id, api_key)
if root is None: continue
for train in root.findall('.//s'):
dp = train.find('dp')
tl = train.find('tl')
if dp is None or tl is None: continue
path = dp.get('ppth', '')
if dest_info['name'].lower() in path.lower() or destination.lower() in path.lower():
pt = dp.get('pt', '')
if not pt: continue
dep_dt = datetime.strptime(pt, "%y%m%d%H%M")
if dep_dt >= now:
arr_time_str = "N/A"
duration_str = "N/A"
arrival_root = fetch_timetable_hour(dest_info['eva'], dep_dt.strftime("%y%m%d"), dep_dt.strftime("%H"), client_id, api_key)
if arrival_root is not None:
for arr_train in arrival_root.findall('.//s'):
arr_tl = arr_train.find('tl')
arr_ar = arr_train.find('ar')
if arr_tl is not None and arr_ar is not None:
if arr_tl.get('n') == tl.get('n'):
arr_pt = arr_ar.get('pt', '')
arr_dt = datetime.strptime(arr_pt, "%y%m%d%H%M")
arr_time_str = arr_dt.strftime("%H:%M")
diff = arr_dt - dep_dt
duration_str = f"{int(diff.total_seconds() // 60)} min"
break
found_connections.append({
"startort": dep_info['name'],
"zielort": dest_info['name'],
"abfahrtszeit": dep_dt.strftime("%H:%M"),
"ankunftszeitszeit": arr_time_str,
"gleis": dp.get('pp', 'n/a'),
"duration": duration_str,
"_dt": dep_dt
})
found_connections.sort(key=lambda x: x['_dt'])
return [{k: v for k, v in c.items() if k != "_dt"} for c in found_connections[:3]]
# --- Gradio UI ---
def ui_wrapper(dep, dest):
if not CLIENT_ID or not API_KEY:
error_result = {"error": "API-Anmeldeinformationen nicht konfiguriert."}
error_markdown = "**Fehler:** API-Anmeldeinformationen nicht konfiguriert."
return error_result, error_markdown
results = search_next_3_connections(dep, dest, CLIENT_ID, API_KEY)
markdown_table = json_to_markdown_table(results)
return results, markdown_table
with gr.Blocks(title="DB JSON Fahrplan", theme=gr.themes.Soft()) as demo:
gr.Markdown("# 🚆 DB │ Deutsche Bahn Zugverbindungen")
with gr.Row():
dep_input = gr.Textbox(label="Abfahrtsort", placeholder="z.B. Schweinfurt Hbf")
dest_input = gr.Textbox(label="Zielort", placeholder="z.B. Oerlenbach")
btn = gr.Button("🔍 Suchen", variant="primary")
gr.Markdown("### JSON Ergebnis")
output = gr.JSON(label="Rohdaten")
gr.Markdown("### Formatierte Tabelle")
md_output = gr.Markdown()
btn.click(fn=ui_wrapper, inputs=[dep_input, dest_input], outputs=[output, md_output])
if __name__ == "__main__":
demo.launch(mcp_server=True)