mgokg commited on
Commit
fd470c7
·
verified ·
1 Parent(s): c1358c4

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +46 -79
app.py CHANGED
@@ -3,7 +3,6 @@ import requests
3
  from datetime import datetime, timedelta
4
  import xml.etree.ElementTree as ET
5
  import json
6
- import os
7
 
8
  def get_station_info(pattern, client_id, api_key):
9
  """Ermittelt EVA-Nummer und offiziellen Namen."""
@@ -40,122 +39,90 @@ def fetch_timetable_hour(eva, date_str, hour_str, client_id, api_key):
40
  pass
41
  return None
42
 
43
- def fetch_journey_details(journey_id, client_id, api_key):
44
- """Ruft die detaillierten Journey-Informationen ab."""
45
- url = f"https://apis.deutschebahn.com/db-api-marketplace/apis/timetables/v1/journeyDetails/{journey_id}"
46
- headers = {
47
- 'DB-Client-Id': client_id,
48
- 'DB-Api-Key': api_key,
49
- 'accept': 'application/xml'
50
- }
51
- try:
52
- response = requests.get(url, headers=headers, timeout=10)
53
- if response.status_code == 200:
54
- return ET.fromstring(response.content)
55
- except Exception:
56
- pass
57
- return None
58
-
59
- def search_next_3_connections(departure, destination):
60
  """Hauptfunktion: Findet die nächsten 3 Verbindungen ab 'jetzt'."""
61
- client_id = os.getenv('client_id')
62
- api_key = os.getenv('api_key')
63
  if not all([departure, destination, client_id, api_key]):
64
- return {"error": "Bitte alle Felder ausfüllen oder Umgebungsvariablen setzen."}
65
 
66
  # 1. IBNRs ermitteln
67
  dep_info = get_station_info(departure, client_id, api_key)
68
  dest_info = get_station_info(destination, client_id, api_key)
69
- if not dep_info:
70
- return {"error": f"Startort '{departure}' nicht gefunden."}
71
- if not dest_info:
72
- return {"error": f"Zielort '{destination}' nicht gefunden."}
73
 
74
  now = datetime.now()
75
  found_connections = []
76
-
77
- # 2. Suche in der aktuellen und den nächsten Stunden (um 3 Verbindungen zu garantieren)
78
- for hour_offset in range(3): # Wir schauen bis zu 2 Stunden voraus
79
  search_time = now + timedelta(hours=hour_offset)
80
  datum = search_time.strftime("%y%m%d")
81
  stunde = search_time.strftime("%H")
 
82
  root = fetch_timetable_hour(dep_info['eva'], datum, stunde, client_id, api_key)
83
- if root is None:
84
- continue
85
  for train in root.findall('.//s'):
86
  dp = train.find('dp')
87
- if dp is None:
88
- continue
89
  # Prüfen ob Ziel im geplanten Pfad (ppth)
90
  path = dp.get('ppth', '')
91
- if dest_info['name'].lower() not in path.lower() and destination.lower() not in path.lower():
92
- continue
93
- pt = dp.get('pt', '') # Geplante Zeit: YYMMDDHHMM
94
- if not pt:
95
- continue
96
- dep_dt = datetime.strptime(pt, "%y%m%d%H%M")
97
- # Nur Verbindungen in der Zukunft (ab Zeitstempel jetzt)
98
- if dep_dt < now:
99
- continue
100
- # Hole Journey Details
101
- journey_id = train.get('id')
102
- if not journey_id:
103
- continue
104
- details_root = fetch_journey_details(journey_id, client_id, api_key)
105
- if details_root is None:
106
- continue
107
- # Finde den Stop am Ziel
108
- arr_dt = None
109
- for stop in details_root.findall('.//stop'):
110
- if stop.get('eva') == dest_info['eva']:
111
- ar = stop.find('ar')
112
- if ar is not None:
113
- arr_pt = ar.get('pt', '')
114
- if arr_pt:
115
- arr_dt = datetime.strptime(arr_pt, "%y%m%d%H%M")
116
- break
117
- if arr_dt is None:
118
- continue # Ziel nicht gefunden oder keine Ankunftszeit
119
- # Berechne Duration
120
- duration_delta = arr_dt - dep_dt
121
- duration_minutes = int(duration_delta.total_seconds() / 60)
122
- duration_str = f"{duration_minutes // 60:02d}:{duration_minutes % 60:02d}"
123
- tl = train.find('tl')
124
- found_connections.append({
125
- "startort": dep_info['name'],
126
- "zielort": dest_info['name'],
127
- "abfahrtszeit": dep_dt.strftime("%H:%M"),
128
- "ankunftszeit": arr_dt.strftime("%H:%M"),
129
- "duration": duration_str,
130
- "gleis": dp.get('pp', 'n/a'),
131
- "zug": f"{tl.get('c', '')} {tl.get('n', '')}",
132
- "_dt": dep_dt # Hilfsfeld zum Sortieren
133
- })
134
 
135
  # 3. Sortieren und Top 3 auswählen
136
  found_connections.sort(key=lambda x: x['_dt'])
 
137
  # Bereinigen der Ergebnisse für die JSON-Ausgabe
138
  final_results = []
139
  for c in found_connections[:3]:
140
  # Entferne das interne Datetime-Objekt vor der JSON-Konvertierung
141
  res = {k: v for k, v in c.items() if k != "_dt"}
142
  final_results.append(res)
 
143
  return final_results
144
 
145
  # --- Gradio UI ---
146
- def ui_wrapper(dep, dest):
147
- results = search_next_3_connections(dep, dest)
 
148
  return json.dumps(results, indent=4, ensure_ascii=False)
149
 
150
  with gr.Blocks(title="DB JSON Fahrplan", theme=gr.themes.Soft()) as demo:
151
  gr.Markdown("# 🚆 DB Verbindungs-Suche (JSON)")
152
  gr.Markdown("Ermittelt die nächsten 3 Verbindungen ab dem aktuellen Zeitstempel.")
 
 
 
 
 
153
  with gr.Row():
154
  dep_input = gr.Textbox(label="Abfahrtsort", placeholder="z.B. Berlin")
155
  dest_input = gr.Textbox(label="Zielort", placeholder="z.B. Hamburg")
 
156
  btn = gr.Button("Suchen", variant="primary")
157
- output = gr.JSON(label="JSON Ergebnis") # Nutzt Gradio JSON Komponente für schöneres Format
158
- btn.click(fn=ui_wrapper, inputs=[dep_input, dest_input], outputs=output)
 
159
 
160
  if __name__ == "__main__":
161
  demo.launch()
 
3
  from datetime import datetime, timedelta
4
  import xml.etree.ElementTree as ET
5
  import json
 
6
 
7
  def get_station_info(pattern, client_id, api_key):
8
  """Ermittelt EVA-Nummer und offiziellen Namen."""
 
39
  pass
40
  return None
41
 
42
+ def search_next_3_connections(departure, destination, client_id, api_key):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
43
  """Hauptfunktion: Findet die nächsten 3 Verbindungen ab 'jetzt'."""
44
+
 
45
  if not all([departure, destination, client_id, api_key]):
46
+ return {"error": "Bitte alle Felder ausfüllen."}
47
 
48
  # 1. IBNRs ermitteln
49
  dep_info = get_station_info(departure, client_id, api_key)
50
  dest_info = get_station_info(destination, client_id, api_key)
51
+
52
+ if not dep_info: return {"error": f"Startort '{departure}' nicht gefunden."}
53
+ if not dest_info: return {"error": f"Zielort '{destination}' nicht gefunden."}
 
54
 
55
  now = datetime.now()
56
  found_connections = []
57
+
58
+ # 2. Suche in der aktuellen und der nächsten Stunde (um 3 Verbindungen zu garantieren)
59
+ for hour_offset in range(3): # Wir schauen bis zu 2 Stunden voraus
60
  search_time = now + timedelta(hours=hour_offset)
61
  datum = search_time.strftime("%y%m%d")
62
  stunde = search_time.strftime("%H")
63
+
64
  root = fetch_timetable_hour(dep_info['eva'], datum, stunde, client_id, api_key)
65
+ if root is None: continue
66
+
67
  for train in root.findall('.//s'):
68
  dp = train.find('dp')
69
+ if dp is None: continue
70
+
71
  # Prüfen ob Ziel im geplanten Pfad (ppth)
72
  path = dp.get('ppth', '')
73
+ if dest_info['name'].lower() in path.lower() or destination.lower() in path.lower():
74
+
75
+ pt = dp.get('pt', '') # Geplante Zeit: YYMMDDHHMM
76
+ if not pt: continue
77
+
78
+ dep_dt = datetime.strptime(pt, "%y%m%d%H%M")
79
+
80
+ # Nur Verbindungen in der Zukunft (ab Zeitstempel jetzt)
81
+ if dep_dt >= now:
82
+ tl = train.find('tl')
83
+ found_connections.append({
84
+ "startort": dep_info['name'],
85
+ "zielort": dest_info['name'],
86
+ "abfahrtszeit": dep_dt.strftime("%d.%m.%Y %H:%M"),
87
+ "gleis": dp.get('pp', 'n/a'),
88
+ "zug": f"{tl.get('c', '')} {tl.get('n', '')}",
89
+ "_dt": dep_dt # Hilfsfeld zum Sortieren
90
+ })
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
91
 
92
  # 3. Sortieren und Top 3 auswählen
93
  found_connections.sort(key=lambda x: x['_dt'])
94
+
95
  # Bereinigen der Ergebnisse für die JSON-Ausgabe
96
  final_results = []
97
  for c in found_connections[:3]:
98
  # Entferne das interne Datetime-Objekt vor der JSON-Konvertierung
99
  res = {k: v for k, v in c.items() if k != "_dt"}
100
  final_results.append(res)
101
+
102
  return final_results
103
 
104
  # --- Gradio UI ---
105
+
106
+ def ui_wrapper(dep, dest, cid, akey):
107
+ results = search_next_3_connections(dep, dest, cid, akey)
108
  return json.dumps(results, indent=4, ensure_ascii=False)
109
 
110
  with gr.Blocks(title="DB JSON Fahrplan", theme=gr.themes.Soft()) as demo:
111
  gr.Markdown("# 🚆 DB Verbindungs-Suche (JSON)")
112
  gr.Markdown("Ermittelt die nächsten 3 Verbindungen ab dem aktuellen Zeitstempel.")
113
+
114
+ with gr.Row():
115
+ cid_input = gr.Textbox(label="DB Client ID", type="password")
116
+ akey_input = gr.Textbox(label="DB API Key", type="password")
117
+
118
  with gr.Row():
119
  dep_input = gr.Textbox(label="Abfahrtsort", placeholder="z.B. Berlin")
120
  dest_input = gr.Textbox(label="Zielort", placeholder="z.B. Hamburg")
121
+
122
  btn = gr.Button("Suchen", variant="primary")
123
+ output = gr.JSON(label="JSON Ergebnis") # Nutzt Gradio JSON Komponente für schöneres Format
124
+
125
+ btn.click(fn=ui_wrapper, inputs=[dep_input, dest_input, cid_input, akey_input], outputs=output)
126
 
127
  if __name__ == "__main__":
128
  demo.launch()