mgokg commited on
Commit
7189de1
·
verified ·
1 Parent(s): 37c70d8

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +84 -89
app.py CHANGED
@@ -3,29 +3,37 @@ import requests
3
  from datetime import datetime
4
  import xml.etree.ElementTree as ET
5
 
6
- # EVA-Nummern für Hauptbahnhöfe
7
- STATION_EVA = {
8
- 'frankfurt': '8000105',
9
- 'berlin': '8011160',
10
- 'münchen': '8000261',
11
- 'hamburg': '8002549',
12
- 'köln': '8000207',
13
- 'stuttgart': '8000096',
14
- 'düsseldorf': '8000085',
15
- 'dortmund': '8000080',
16
- 'essen': '8000098',
17
- 'leipzig': '8010205',
18
- 'bremen': '8000050',
19
- 'dresden': '8010085',
20
- 'hannover': '8000152',
21
- 'nürnberg': '8000284',
22
- 'duisburg': '8000086',
23
- }
 
 
 
 
 
 
 
 
 
24
 
25
- def get_eva_number(station_name):
26
- """Wandelt Stationsnamen in EVA-Nummer um"""
27
- normalized = station_name.lower().strip()
28
- return STATION_EVA.get(normalized)
29
 
30
  def search_connections(departure, destination, client_id, api_key):
31
  """Sucht Verbindungen zwischen zwei Bahnhöfen"""
@@ -36,18 +44,26 @@ def search_connections(departure, destination, client_id, api_key):
36
  if not client_id or not api_key:
37
  return "❌ Bitte Client ID und API Key eingeben"
38
 
39
- # EVA-Nummer für Abfahrtsort ermitteln
40
- departure_eva = get_eva_number(departure)
41
- if not departure_eva:
42
- available = ', '.join(STATION_EVA.keys())
43
- return f"❌ Station '{departure}' nicht gefunden.\n\nVerfügbare Stationen: {available}"
 
 
 
 
 
 
 
 
44
 
45
  # Aktuelles Datum und Stunde
46
  now = datetime.now()
47
  datum = now.strftime("%y%m%d") # YYMMDD
48
  stunde = now.strftime("%H") # HH
49
 
50
- # API-Aufruf
51
  url = f"https://apis.deutschebahn.com/db-api-marketplace/apis/timetables/v1/plan/{departure_eva}/{datum}/{stunde}"
52
 
53
  headers = {
@@ -60,122 +76,101 @@ def search_connections(departure, destination, client_id, api_key):
60
  response = requests.get(url, headers=headers, timeout=10)
61
 
62
  if response.status_code != 200:
63
- return f"❌ API Fehler: {response.status_code} - {response.text[:200]}"
64
 
65
- # XML parsen
66
  root = ET.fromstring(response.content)
67
  connections = []
68
 
69
- # Alle Züge durchgehen
70
  for train in root.findall('.//s'):
71
- # Abfahrtsinformationen
72
  dp = train.find('dp')
73
  if dp is None:
74
  continue
75
 
76
- # Route des Zugs
77
  path = dp.get('ppth', '')
78
 
79
- # Prüfen ob Zielort in Route enthalten ist
80
- if destination.lower() in path.lower():
81
- train_id = train.get('id', 'Unbekannt')
 
 
 
 
 
 
82
  planned_time = dp.get('pt', '')
83
  platform = dp.get('pp', 'n/a')
84
 
85
- # Zeit formatieren (von HHMM zu HH:MM)
86
- if len(planned_time) == 4:
 
87
  planned_time = f"{planned_time[:2]}:{planned_time[2:]}"
88
 
89
- # Route formatieren
90
  route = ' → '.join(path.split('|'))
91
 
92
  connections.append({
93
- 'train': train_id,
94
  'time': planned_time,
95
  'platform': platform,
96
  'route': route
97
  })
98
 
99
- # Ergebnisse formatieren
100
  if not connections:
101
- return f"ℹ️ Keine direkten Verbindungen von {departure.title()} nach {destination.title()} gefunden.\n\nHinweis: Die App sucht nur nach direkten Verbindungen in der nächsten Stunde."
102
 
103
- result = f"🚆 Verbindungen von {departure.title()} nach {destination.title()}\n"
104
- result += f"📅 {now.strftime('%d.%m.%Y')} ab {now.strftime('%H:00')} Uhr\n\n"
 
105
 
106
- for i, conn in enumerate(connections[:10], 1):
107
  result += f"─────────────────────────────────\n"
108
  result += f"{i}. {conn['train']}\n"
109
  result += f" ⏰ Abfahrt: {conn['time']} Uhr\n"
110
  result += f" 🚉 Gleis: {conn['platform']}\n"
111
- result += f" 🗺️ Route: {conn['route']}\n\n"
112
 
113
  return result
114
 
115
- except requests.exceptions.Timeout:
116
- return "❌ Zeitüberschreitung bei der API-Anfrage"
117
- except requests.exceptions.RequestException as e:
118
- return f"❌ Netzwerkfehler: {str(e)}"
119
- except ET.ParseError as e:
120
- return f"❌ Fehler beim Parsen der XML-Antwort: {str(e)}"
121
  except Exception as e:
122
- return f"❌ Unerwarteter Fehler: {str(e)}"
123
 
124
- # Gradio Interface erstellen
125
- with gr.Blocks(title="Deutsche Bahn Fahrplanauskunft", theme=gr.themes.Soft()) as demo:
126
  gr.Markdown(
127
  """
128
- # 🚆 Deutsche Bahn Fahrplanauskunft
129
- Finden Sie Zugverbindungen mit der DB Timetable API
130
  """
131
  )
132
 
133
  with gr.Row():
134
  with gr.Column():
135
- client_id_input = gr.Textbox(
136
- label="DB Client ID",
137
- placeholder="Ihre Client ID von developers.deutschebahn.com",
138
- type="password"
139
- )
140
- api_key_input = gr.Textbox(
141
- label="DB API Key",
142
- placeholder="Ihr API Key",
143
- type="password"
144
- )
145
 
146
  with gr.Row():
147
  with gr.Column():
148
  departure_input = gr.Textbox(
149
- label="Abfahrtsort",
150
- placeholder="z.B. Frankfurt",
151
- value=""
152
  )
153
  with gr.Column():
154
  destination_input = gr.Textbox(
155
- label="Zielort",
156
- placeholder="z.B. Berlin",
157
- value=""
158
  )
159
 
160
- gr.Markdown(" **Abfahrtszeit:** Jetzt (automatisch)")
161
 
162
- search_button = gr.Button("🔍 Verbindungen suchen", variant="primary", size="lg")
163
-
164
- output = gr.Textbox(
165
- label="Ergebnisse",
166
- lines=20,
167
- max_lines=30
168
- )
169
 
170
  gr.Markdown(
171
- f"""
172
- ### 📍 Verfügbare Stationen
173
- {', '.join(sorted(STATION_EVA.keys()))}
174
-
175
- ### ℹ️ Hinweise
176
- - Sie benötigen einen kostenlosen API-Zugang von [DB API Marketplace](https://developers.deutschebahn.com)
177
- - Die App sucht nach direkten Verbindungen in der aktuellen Stunde
178
- - Geben Sie Städtenamen ohne "Hbf" ein (z.B. "Frankfurt" statt "Frankfurt Hbf")
179
  """
180
  )
181
 
 
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"""
 
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 = {
 
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