ErzhanAb commited on
Commit
ebacc7b
·
verified ·
1 Parent(s): 4a34d0b

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +43 -44
app.py CHANGED
@@ -71,31 +71,18 @@ def find_fastest_route(G, start_node, end_node, weight='travel_time'):
71
  return None, None
72
 
73
  def plot_route_on_map(G, route, start_point, end_point):
74
- """Отрисовывает один маршрут на стильной и минималистичной карте Folium."""
75
- # Используем минималистичные тайлы 'CartoDB positron' для чистого вида
76
  m = folium.Map(tiles="CartoDB positron", attr='&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors &copy; <a href="https://carto.com/attributions">CARTO</a>')
77
 
78
  if route:
79
  points = [(G.nodes[node]['y'], G.nodes[node]['x']) for node in route]
80
-
81
- # Белая "подложка" для контраста и лучшей видимости
82
- folium.PolyLine(points, color="white", weight=10, opacity=0.8).add_to(m)
83
- # Основная линия маршрута - яркий, приятный синий цвет
84
- main_line = folium.PolyLine(points, color="#007FFF", weight=5, opacity=1, tooltip="Оптимальный маршрут")
85
  main_line.add_to(m)
86
-
87
- # Автоматическая настройка масштаба карты под маршрут
88
  m.fit_bounds(main_line.get_bounds(), padding=(30, 30))
89
 
90
- # Стильные маркеры для старта и финиша
91
- folium.Marker(
92
- location=start_point, popup="<b>Старт</b>",
93
- icon=folium.Icon(color="green", icon="play", prefix='fa')
94
- ).add_to(m)
95
- folium.Marker(
96
- location=end_point, popup="<b>Финиш</b>",
97
- icon=folium.Icon(color="red", icon="flag-checkered", prefix='fa')
98
- ).add_to(m)
99
 
100
  return m
101
 
@@ -106,7 +93,7 @@ print("✅ Вспомогательные функции готовы.")
106
  # ==============================================================================
107
  print("\n🚀 Шаг 5: Настройка и запуск веб-интерфейса Gradio...")
108
 
109
- geolocator = Nominatim(user_agent="bishkek_navigator_app_v3")
110
  geocode = RateLimiter(geolocator.geocode, min_delay_seconds=1)
111
 
112
  def find_and_plot_route_by_address(start_address, end_address, day_of_week, hour, minute):
@@ -125,66 +112,78 @@ def find_and_plot_route_by_address(start_address, end_address, day_of_week, hour
125
  start_node = ox.nearest_nodes(G, Y=start_point[0], X=start_point[1])
126
  end_node = ox.nearest_nodes(G, Y=end_point[0], X=end_point[1])
127
 
128
- # Устанавливаем веса ребер графа на основе прогноза модели
129
  selected_time = datetime.datetime(2023, 1, 2 + day_of_week, int(hour), int(minute))
130
  travel_times = predict_graph_weights(gdf_edges, model, selected_time)
131
  nx.set_edge_attributes(G, values=pd.Series(travel_times, index=gdf_edges.index).to_dict(), name='travel_time')
132
 
133
- # Ищем единственный лучший маршрут
134
  route, travel_time = find_fastest_route(G, start_node, end_node, weight='travel_time')
135
  if route is None:
136
  return None, "### ❌ Ошибка\nНе удалось построить маршрут. Возможно, точки находятся в несвязанных частях города."
137
 
138
- # Расчет итоговых параметров маршрута
139
  SIGNAL_DELAY_SECONDS = 30
140
  signals_on_route = sum(1 for node in route if node in signal_nodes_set)
141
  total_time_sec = travel_time + signals_on_route * SIGNAL_DELAY_SECONDS
142
  total_time_min = total_time_sec / 60
143
  distance_km = sum(G[u][v][0]['length'] for u, v in zip(route[:-1], route[1:])) / 1000
144
 
145
- # Создание карты
146
  final_map = plot_route_on_map(G, route, start_point, end_point)
147
 
148
- # Форматирование вывода в Markdown
149
  output_md = f"""
150
- ### ✅ Маршрут построен!
151
- - **Время в пути:** <span style="font-size: 1.1em; color: #007FFF;">**~{total_time_min:.1f} мин.**</span>
152
- - **Расстояние:** **{distance_km:.2f} км**
153
- - **Светофоров на пути:** **{signals_on_route}**
 
154
  """
155
- return final_map._repr_html_(), output_md
156
 
157
  except Exception as e:
158
  return None, f"### 💥 Произошла внутренняя ошибка:\n`{e}`"
159
 
160
- # CSS для стилизации интерфейса
161
  css = """
162
- body { font-family: 'Inter', sans-serif; background-color: #f7fafc; }
163
- .gradio-container { max-width: 1200px !important; margin: auto !important; padding-top: 2rem; }
164
- #map-output div { border-radius: 1rem; overflow: hidden; box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05); }
 
 
165
  .gr-button-primary {
166
- background: linear-gradient(to right, #43e97b 0%, #38f9d7 100%);
167
- color: #1a202c; font-weight: bold; border: none; transition: all 0.3s ease; box-shadow: 0 4px 6px rgba(0,0,0,0.1);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
168
  }
169
- .gr-button-primary:hover { box-shadow: 0 7px 14px rgba(67, 233, 123, 0.3); transform: translateY(-2px); }
170
- #info-box { background-color: white; padding: 1.5rem !important; border-radius: 1rem; box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px 0 rgba(0, 0, 0, 0.06); }
171
  """
172
 
173
- with gr.Blocks(theme=gr.themes.Soft(primary_hue="teal", secondary_hue="gray"), css=css) as demo:
174
  gr.Markdown(
175
  """
176
- <div style="text-align: center;">
177
- <h1 style="font-size: 2.5rem; font-weight: 700;">🗺️ Умный навигатор по Бишкеку</h1>
178
- <p style="color: #4A5568; font-size: 1.1rem;">Постройте оптимальный маршрут с учётом прогноза пробок</p>
179
  </div>
180
  """
181
  )
182
  with gr.Row(equal_height=False):
183
  with gr.Column(scale=1):
184
- # ИСПРАВЛЕНИЕ: gr.Box() заменен на gr.Group() для совместимости
185
  with gr.Group():
186
- start_address_input = gr.Textbox(label="Откуда?", placeholder="Например, ЦУМ")
187
- end_address_input = gr.Textbox(label="Куда?", placeholder="Например, парк Ата-Тюрк")
188
 
189
  with gr.Accordion("🗓️ Указать время и дату", open=False):
190
  day_dropdown = gr.Dropdown(label="День недели", choices=["Понедельник", "Вторник", "Среда", "Четверг", "Пятница", "Суббота", "Воскресенье"], value="Понедельник", type="index")
 
71
  return None, None
72
 
73
  def plot_route_on_map(G, route, start_point, end_point):
74
+ """Отрисовывает один маршрут на стильной карте, как в скриншоте."""
 
75
  m = folium.Map(tiles="CartoDB positron", attr='&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors &copy; <a href="https://carto.com/attributions">CARTO</a>')
76
 
77
  if route:
78
  points = [(G.nodes[node]['y'], G.nodes[node]['x']) for node in route]
79
+ main_line = folium.PolyLine(points, color="#007FFF", weight=5, opacity=0.9)
 
 
 
 
80
  main_line.add_to(m)
 
 
81
  m.fit_bounds(main_line.get_bounds(), padding=(30, 30))
82
 
83
+ # Маркеры, как в скриншоте: красный - старт, зеленый - финиш
84
+ folium.Marker(location=start_point, popup="<b>Старт</b>", icon=folium.Icon(color="red")).add_to(m)
85
+ folium.Marker(location=end_point, popup="<b>Финиш</b>", icon=folium.Icon(color="green")).add_to(m)
 
 
 
 
 
 
86
 
87
  return m
88
 
 
93
  # ==============================================================================
94
  print("\n🚀 Шаг 5: Настройка и запуск веб-интерфейса Gradio...")
95
 
96
+ geolocator = Nominatim(user_agent="bishkek_navigator_app_v4")
97
  geocode = RateLimiter(geolocator.geocode, min_delay_seconds=1)
98
 
99
  def find_and_plot_route_by_address(start_address, end_address, day_of_week, hour, minute):
 
112
  start_node = ox.nearest_nodes(G, Y=start_point[0], X=start_point[1])
113
  end_node = ox.nearest_nodes(G, Y=end_point[0], X=end_point[1])
114
 
 
115
  selected_time = datetime.datetime(2023, 1, 2 + day_of_week, int(hour), int(minute))
116
  travel_times = predict_graph_weights(gdf_edges, model, selected_time)
117
  nx.set_edge_attributes(G, values=pd.Series(travel_times, index=gdf_edges.index).to_dict(), name='travel_time')
118
 
 
119
  route, travel_time = find_fastest_route(G, start_node, end_node, weight='travel_time')
120
  if route is None:
121
  return None, "### ❌ Ошибка\nНе удалось построить маршрут. Возможно, точки находятся в несвязанных частях города."
122
 
 
123
  SIGNAL_DELAY_SECONDS = 30
124
  signals_on_route = sum(1 for node in route if node in signal_nodes_set)
125
  total_time_sec = travel_time + signals_on_route * SIGNAL_DELAY_SECONDS
126
  total_time_min = total_time_sec / 60
127
  distance_km = sum(G[u][v][0]['length'] for u, v in zip(route[:-1], route[1:])) / 1000
128
 
 
129
  final_map = plot_route_on_map(G, route, start_point, end_point)
130
 
131
+ # Форматирование вывода в Markdown, как на скриншоте
132
  output_md = f"""
133
+ **✅ Маршрут построен!**
134
+
135
+ * Время в пут��: ~{total_time_min:.1f} мин.
136
+ * Расстояние: {distance_km:.2f} км
137
+ * Светофоров на пути: {signals_on_route}
138
  """
139
+ return final_map._repr_html_(), output_md.replace(" *", "*") # Убираем лишние отступы для Markdown
140
 
141
  except Exception as e:
142
  return None, f"### 💥 Произошла внутренняя ошибка:\n`{e}`"
143
 
144
+ # CSS для стилизации интерфейса под дизайн со скриншота
145
  css = """
146
+ body, .gradio-container { background-color: #f0fdfa; font-family: 'Inter', sans-serif; }
147
+ .gradio-container { max-width: 1200px !important; margin: auto !important; padding-top: 1.5rem; }
148
+ /* Стили для карты */
149
+ #map-output { border-radius: 1.5rem; overflow: hidden; box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05); }
150
+ /* Стили для кнопки */
151
  .gr-button-primary {
152
+ background-color: #14b8a6; color: white; font-weight: bold; border-radius: 0.75rem; border: none;
153
+ box-shadow: 0 4px 6px rgba(20, 184, 166, 0.2); transition: all 0.2s ease; padding: 12px 0;
154
+ }
155
+ .gr-button-primary:hover { background-color: #0d9488; box-shadow: 0 7px 10px rgba(20, 184, 166, 0.3); transform: translateY(-2px); }
156
+ /* Стили для информационного блока с результатом */
157
+ #info-box { background-color: white; padding: 1.5rem !important; border-radius: 1rem; box-shadow: 0 4px 6px -1px rgba(0,0,0,0.1), 0 2px 4px -1px rgba(0,0,0,0.06); }
158
+ /* Стили для меток (Откуда?, Куда?, и т.д.) */
159
+ .gradio-container .form .gr-label span {
160
+ background-color: #ccfbf1; color: #134e4a; padding: 5px 12px;
161
+ border-radius: 9999px; font-size: 0.8em; font-weight: 600;
162
+ display: inline-block; margin-bottom: 6px;
163
+ }
164
+ /* Стили для полей ввода */
165
+ .gradio-container .gr-input-text, .gradio-container .gr-dropdown {
166
+ border-radius: 0.75rem !important; border-color: #cbd5e1 !important;
167
+ }
168
+ .gradio-container .gr-input-text:focus, .gradio-container .gr-dropdown:focus {
169
+ border-color: #14b8a6 !important; box-shadow: 0 0 0 2px rgba(20, 184, 166, 0.3) !important;
170
  }
 
 
171
  """
172
 
173
+ with gr.Blocks(theme=gr.themes.Soft(primary_hue="teal", secondary_hue="gray", font=gr.themes.GoogleFont("Inter")), css=css) as demo:
174
  gr.Markdown(
175
  """
176
+ <div style="text-align: center; margin-bottom: 2rem;">
177
+ <h1 style="font-size: 2.5rem; font-weight: 700; color: #0f766e;">🗺️ Умный навигатор по Бишкеку</h1>
178
+ <p style="color: #0d9488; font-size: 1.1rem;">Постройте оптимальный маршрут с учётом прогноза пробок</p>
179
  </div>
180
  """
181
  )
182
  with gr.Row(equal_height=False):
183
  with gr.Column(scale=1):
 
184
  with gr.Group():
185
+ start_address_input = gr.Textbox(label="Откуда?", placeholder="7 микрорайон")
186
+ end_address_input = gr.Textbox(label="Куда?", placeholder="Ошский рынок")
187
 
188
  with gr.Accordion("🗓️ Указать время и дату", open=False):
189
  day_dropdown = gr.Dropdown(label="День недели", choices=["Понедельник", "Вторник", "Среда", "Четверг", "Пятница", "Суббота", "Воскресенье"], value="Понедельник", type="index")