mgokg commited on
Commit
2c877f9
·
verified ·
1 Parent(s): bcf09fd

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +72 -155
app.py CHANGED
@@ -1,187 +1,104 @@
1
- import gradio as gr
2
  import requests
3
- from datetime import datetime
4
  import xml.etree.ElementTree as ET
 
 
5
 
6
  def get_station_info(pattern, client_id, api_key):
7
- """
8
- Sucht über die Timetables API nach einem Bahnhof und gibt EVA-Nummer
9
- und den korrekten Namen zurück.
10
- """
11
  url = f"https://apis.deutschebahn.com/db-api-marketplace/apis/timetables/v1/station/{pattern}"
 
12
 
13
- headers = {
14
- 'DB-Client-Id': client_id,
15
- 'DB-Api-Key': api_key,
16
- 'accept': 'application/xml'
17
- }
18
-
19
  try:
20
  response = requests.get(url, headers=headers, timeout=10)
21
  response.raise_for_status()
22
-
23
  root = ET.fromstring(response.content)
24
- stations = []
25
- for station in root.findall('station'):
26
- stations.append({
27
- 'name': station.get('name'),
28
- 'eva': station.get('eva')
29
- })
30
-
31
- # Falls Stationen gefunden wurden, nehmen wir die erste (beste Übereinstimmung)
32
- return stations[0] if stations else None
33
-
34
- except Exception as e:
35
- print(f"Fehler bei Stationssuche: {e}")
36
  return None
 
37
 
38
- def search_connections(departure, destination, client_id, api_key):
39
- """Sucht Verbindungen zwischen zwei Bahnhöfen"""
40
-
41
- if not departure or not destination:
42
- return "❌ Bitte Abfahrts- und Zielort eingeben"
43
 
44
- if not client_id or not api_key:
45
- return "❌ Bitte Client ID und API Key eingeben"
 
 
 
 
 
 
 
 
46
 
47
- # 1. IBNR (EVA) für Abfahrtsort ermitteln
48
- dep_info = get_station_info(departure, client_id, api_key)
49
- if not dep_info:
50
- return f"❌ Abfahrtsort '{departure}' wurde nicht gefunden."
51
 
52
- # 2. IBNR (EVA) für Zielort ermitteln (für genaueres Matching im Pfad)
53
- dest_info = get_station_info(destination, client_id, api_key)
54
- if not dest_info:
55
- return f"❌ Zielort '{destination}' wurde nicht gefunden."
56
 
57
- departure_eva = dep_info['eva']
58
- departure_name = dep_info['name']
59
- destination_name = dest_info['name']
60
-
61
- # Aktuelles Datum und Stunde
62
  now = datetime.now()
63
- datum = now.strftime("%y%m%d") # YYMMDD
64
- stunde = now.strftime("%H") # HH
65
-
66
- # API-Aufruf für den Fahrplan
67
- url = f"https://apis.deutschebahn.com/db-api-marketplace/apis/timetables/v1/plan/{departure_eva}/{datum}/{stunde}"
68
 
69
- headers = {
70
- "DB-Client-Id": client_id,
71
- "DB-Api-Key": api_key,
72
- "accept": "application/xml"
73
- }
74
-
75
- try:
76
- response = requests.get(url, headers=headers, timeout=10)
77
-
78
- if response.status_code != 200:
79
- return f"❌ API Fehler beim Abrufen des Fahrplans: {response.status_code}"
80
-
81
- root = ET.fromstring(response.content)
82
- connections = []
83
 
 
 
 
 
84
  for train in root.findall('.//s'):
85
  dp = train.find('dp')
86
- if dp is None:
87
- continue
88
 
89
- # Route des Zugs (ppth = planned path)
90
  path = dp.get('ppth', '')
91
-
92
- # Prüfen ob Zielort im Pfad enthalten ist
93
- # Wir prüfen sowohl den eingegebenen Namen als auch den gefundenen offiziellen Namen
94
- if destination_name.lower() in path.lower() or destination.lower() in path.lower():
95
- # Zugdetails extrahieren
96
- tl = train.find('tl') # Train Label
97
- train_class = tl.get('c', '') # z.B. ICE
98
- train_number = tl.get('n', '') # z.B. 123
99
- full_train_name = f"{train_class} {train_number}"
100
-
101
- planned_time = dp.get('pt', '')
102
- platform = dp.get('pp', 'n/a')
103
 
104
- if len(planned_time) == 10: # Format YYMMDDHHMM
105
- planned_time = f"{planned_time[8:10]}:{planned_time[10:12]}"
106
- elif len(planned_time) == 4:
107
- planned_time = f"{planned_time[:2]}:{planned_time[2:]}"
108
 
109
- route = ' '.join(path.split('|'))
 
110
 
111
- connections.append({
112
- 'train': full_train_name,
113
- 'time': planned_time,
114
- 'platform': platform,
115
- 'route': route
116
- })
117
-
118
- if not connections:
119
- return f"ℹ️ Keine direkten Verbindungen von {departure_name} nach {destination_name} gefunden.\n(Suche im Zeitraum {now.strftime('%H:00')} - {int(now.strftime('%H'))+1}:00 Uhr)"
120
-
121
- result = f"🚆 Verbindungen von: {departure_name}\n"
122
- result += f"🏁 Ziel: {destination_name}\n"
123
- result += f"📅 Datum: {now.strftime('%d.%m.%Y')}\n\n"
124
-
125
- for i, conn in enumerate(connections[:15], 1):
126
- result += f"─────────────────────────────────\n"
127
- result += f"{i}. {conn['train']}\n"
128
- result += f" ⏰ Abfahrt: {conn['time']} Uhr\n"
129
- result += f" 🚉 Gleis: {conn['platform']}\n"
130
- result += f" 🗺️ Route: {conn['route'][:100]}...\n\n"
131
-
132
- return result
133
-
134
- except Exception as e:
135
- return f"❌ Fehler: {str(e)}"
136
 
137
- # Gradio Interface
138
- with gr.Blocks(title="DB Timetable API - Live Suche", theme=gr.themes.Soft()) as demo:
139
- gr.Markdown(
140
- """
141
- # 🚆 DB Live-Fahrplanauskunft
142
- Ermittelt automatisch die IBNR (EVA-Nummer) und sucht nach Verbindungen.
143
- """
144
- )
145
-
146
- with gr.Row():
147
- with gr.Column():
148
- client_id_input = gr.Textbox(label="DB Client ID", type="password")
149
- api_key_input = gr.Textbox(label="DB API Key", type="password")
150
 
151
- with gr.Row():
152
- with gr.Column():
153
- departure_input = gr.Textbox(
154
- label="Abfahrtsort",
155
- placeholder="z.B. Berlin Hbf oder Frankfurt"
156
- )
157
- with gr.Column():
158
- destination_input = gr.Textbox(
159
- label="Zielort",
160
- placeholder="z.B. München Hbf"
161
- )
162
-
163
- search_button = gr.Button("🔍 Verbindungen suchen", variant="primary")
164
-
165
- output = gr.Textbox(label="Ergebnisse", lines=20)
166
-
167
- gr.Markdown(
168
- """
169
- ### ℹ️ Funktionsweise
170
- 1. Die App sendet Ihren Suchbegriff an den `/station` Endpoint.
171
- 2. Die erste gefundene **EVA-Nummer (IBNR)** wird für die Abfrage genutzt.
172
- 3. Der Fahrplan für die aktuelle Stunde wird abgerufen.
173
- 4. Es wird gefiltert, ob der Zielbahnhof im geplanten Fahrtverlauf vorkommt.
174
- """
175
- )
176
-
177
- search_button.click(
178
- fn=search_connections,
179
- inputs=[departure_input, destination_input, client_id_input, api_key_input],
180
- outputs=output
181
- )
182
 
183
- if __name__ == "__main__":
184
- demo.launch()
185
  """
186
  import gradio as gr
187
  import requests
 
 
1
  import requests
 
2
  import xml.etree.ElementTree as ET
3
+ from datetime import datetime, timedelta
4
+ import json
5
 
6
  def get_station_info(pattern, client_id, api_key):
7
+ """Ermittelt EVA-Nummer und Namen für einen Suchbegriff."""
 
 
 
8
  url = f"https://apis.deutschebahn.com/db-api-marketplace/apis/timetables/v1/station/{pattern}"
9
+ headers = {'DB-Client-Id': client_id, 'DB-Api-Key': api_key, 'accept': 'application/xml'}
10
 
 
 
 
 
 
 
11
  try:
12
  response = requests.get(url, headers=headers, timeout=10)
13
  response.raise_for_status()
 
14
  root = ET.fromstring(response.content)
15
+ station = root.find('station')
16
+ if station is not None:
17
+ return {'name': station.get('name'), 'eva': station.get('eva')}
18
+ except Exception:
 
 
 
 
 
 
 
 
19
  return None
20
+ return None
21
 
22
+ def fetch_timetable_hour(eva, date_str, hour_str, client_id, api_key):
23
+ """Hilt den Fahrplan für eine spezifische Stunde."""
24
+ url = f"https://apis.deutschebahn.com/db-api-marketplace/apis/timetables/v1/plan/{eva}/{date_str}/{hour_str}"
25
+ headers = {'DB-Client-Id': client_id, 'DB-Api-Key': api_key, 'accept': 'application/xml'}
 
26
 
27
+ try:
28
+ response = requests.get(url, headers=headers, timeout=10)
29
+ if response.status_code == 200:
30
+ return ET.fromstring(response.content)
31
+ except Exception:
32
+ pass
33
+ return None
34
+
35
+ def get_next_connections_json(departure_name, destination_name, client_id, api_key):
36
+ """Sucht die nächsten 3 Verbindungen und gibt sie als JSON zurück."""
37
 
38
+ # 1. Stationen auflösen
39
+ dep_info = get_station_info(departure_name, client_id, api_key)
40
+ dest_info = get_station_info(destination_name, client_id, api_key)
 
41
 
42
+ if not dep_info or not dest_info:
43
+ return json.dumps({"error": "Station nicht gefunden"}, indent=4)
 
 
44
 
45
+ # 2. Zeitstempel vorbereiten
 
 
 
 
46
  now = datetime.now()
47
+ all_found_connections = []
 
 
 
 
48
 
49
+ # Wir prüfen die aktuelle und die nächste Stunde, um sicherzugehen, dass wir 3 finden
50
+ for hour_offset in range(2):
51
+ search_time = now + timedelta(hours=hour_offset)
52
+ datum = search_time.strftime("%y%m%d")
53
+ stunde = search_time.strftime("%H")
 
 
 
 
 
 
 
 
 
54
 
55
+ root = fetch_timetable_hour(dep_info['eva'], datum, stunde, client_id, api_key)
56
+ if root is None:
57
+ continue
58
+
59
  for train in root.findall('.//s'):
60
  dp = train.find('dp')
61
+ if dp is None: continue
 
62
 
63
+ # Prüfen ob Ziel im Pfad
64
  path = dp.get('ppth', '')
65
+ if dest_info['name'].lower() in path.lower() or destination_name.lower() in path.lower():
 
 
 
 
 
 
 
 
 
 
 
66
 
67
+ # Zeit-Parsing (Format: YYMMDDHHMM)
68
+ pt = dp.get('pt', '')
69
+ if not pt: continue
 
70
 
71
+ # In datetime Objekt umwandeln für Vergleich und Sortierung
72
+ dep_dt = datetime.strptime(pt, "%y%m%d%H%M")
73
 
74
+ # Nur Züge in der Zukunft berücksichtigen
75
+ if dep_dt >= now:
76
+ all_found_connections.append({
77
+ "startort": dep_info['name'],
78
+ "zielort": dest_info['name'],
79
+ "abfahrtszeit": dep_dt.strftime("%d.%m.%Y %H:%M"),
80
+ "gleis": dp.get('pp', 'n/a'),
81
+ "zug": f"{train.find('tl').get('c')} {train.find('tl').get('n')}",
82
+ "_dt": dep_dt # Intern für Sortierung
83
+ })
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
84
 
85
+ # 3. Sortieren nach Zeit und Top 3 extrahieren
86
+ all_found_connections.sort(key=lambda x: x['_dt'])
 
 
 
 
 
 
 
 
 
 
 
87
 
88
+ # Entferne internes Hilfsfeld _dt und limitiere auf 3
89
+ final_list = []
90
+ for c in all_found_connections[:3]:
91
+ del c['_dt']
92
+ final_list.append(c)
93
+
94
+ return json.dumps(final_list, indent=4, ensure_ascii=False)
95
+
96
+ # --- Beispielaufruf ---
97
+ # client_id = "DEINE_ID"
98
+ # api_key = "DEIN_KEY"
99
+ # print(get_next_connections_json("Frankfurt Hbf", "Berlin", client_id, api_key))
100
+
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
101
 
 
 
102
  """
103
  import gradio as gr
104
  import requests