cngsm commited on
Commit
e317ea5
·
verified ·
1 Parent(s): 17a3db4

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +33 -128
app.py CHANGED
@@ -1,14 +1,9 @@
1
  import gradio as gr
2
  import sqlite3
3
- import json
4
  import pandas as pd
5
- from datetime import datetime, timedelta
6
  import folium
7
  from folium import plugins
8
- import requests
9
- import threading
10
- import time
11
- import os
12
 
13
  # Configuração do banco de dados
14
  def init_db():
@@ -67,7 +62,6 @@ def get_updated_map():
67
  try:
68
  conn = sqlite3.connect('locations.db', check_same_thread=False)
69
 
70
- # Buscar localizações mais recentes de cada dispositivo
71
  query = '''
72
  SELECT device_id, device_name, latitude, longitude,
73
  timestamp, accuracy, battery_level,
@@ -77,12 +71,11 @@ def get_updated_map():
77
  '''
78
 
79
  df = pd.read_sql_query(query, conn)
80
- df_latest = df[df['rn'] == 1].copy() # Apenas a localização mais recente de cada dispositivo
81
 
82
  conn.close()
83
 
84
  if df_latest.empty:
85
- # Mapa padrão centrado no Brasil
86
  m = folium.Map(location=[-14.235, -51.9253], zoom_start=4)
87
  folium.Marker(
88
  [-14.235, -51.9253],
@@ -91,25 +84,20 @@ def get_updated_map():
91
  ).add_to(m)
92
  return m._repr_html_()
93
 
94
- # Criar mapa centrado na média das localizações
95
  center_lat = df_latest['latitude'].mean()
96
  center_lng = df_latest['longitude'].mean()
97
  m = folium.Map(location=[center_lat, center_lng], zoom_start=12)
98
 
99
- # Adicionar marcadores para cada dispositivo
100
  colors = ['red', 'blue', 'green', 'purple', 'orange', 'darkred', 'lightred',
101
  'beige', 'darkblue', 'darkgreen', 'cadetblue', 'darkpurple', 'white', 'pink', 'lightblue', 'lightgreen', 'gray', 'black', 'lightgray']
102
 
103
  for idx, row in df_latest.iterrows():
104
- # Determinar status (online se última atualização foi há menos de 5 min)
105
  last_update = datetime.strptime(row['timestamp'], '%Y-%m-%d %H:%M:%S')
106
- is_online = (datetime.now() - last_update).total_seconds() < 300 # 5 minutos
107
 
108
- # Escolher cor do marcador
109
  color = colors[idx % len(colors)]
110
  icon_color = 'green' if is_online else 'red'
111
 
112
- # Informações do popup
113
  popup_html = f"""
114
  <div style="font-family: Arial; width: 200px;">
115
  <h4>📱 {row['device_name']}</h4>
@@ -130,7 +118,6 @@ def get_updated_map():
130
  icon=folium.Icon(color=icon_color, icon='phone', prefix='fa')
131
  ).add_to(m)
132
 
133
- # Adicionar círculo de precisão
134
  folium.Circle(
135
  [row['latitude'], row['longitude']],
136
  radius=row['accuracy'],
@@ -141,7 +128,6 @@ def get_updated_map():
141
  weight=1
142
  ).add_to(m)
143
 
144
- # Adicionar histórico de movimento (últimas 24h)
145
  for device_id in df_latest['device_id'].unique():
146
  device_history = df[df['device_id'] == device_id].sort_values('timestamp')
147
  if len(device_history) > 1:
@@ -154,10 +140,7 @@ def get_updated_map():
154
  popup=f"Trajeto: {device_history.iloc[0]['device_name']}"
155
  ).add_to(m)
156
 
157
- # Adicionar plugin de tela cheia
158
  plugins.Fullscreen().add_to(m)
159
-
160
- # Adicionar mini mapa
161
  minimap = plugins.MiniMap()
162
  m.add_child(minimap)
163
 
@@ -170,24 +153,20 @@ def get_updated_map():
170
  def get_statistics():
171
  try:
172
  conn = sqlite3.connect('locations.db', check_same_thread=False)
173
-
174
- # Contar dispositivos únicos
175
  cursor = conn.cursor()
 
176
  cursor.execute("SELECT COUNT(DISTINCT device_id) FROM locations")
177
  total_devices = cursor.fetchone()[0]
178
 
179
- # Contar localizações nas últimas 24h
180
  cursor.execute("SELECT COUNT(*) FROM locations WHERE timestamp > datetime('now', '-1 day')")
181
  locations_24h = cursor.fetchone()[0]
182
 
183
- # Dispositivos online (última atualização < 5 min)
184
  cursor.execute("""
185
  SELECT COUNT(DISTINCT device_id) FROM locations
186
  WHERE timestamp > datetime('now', '-5 minutes')
187
  """)
188
  online_devices = cursor.fetchone()[0]
189
 
190
- # Última atualização geral
191
  cursor.execute("SELECT MAX(timestamp) FROM locations")
192
  last_update = cursor.fetchone()[0]
193
 
@@ -212,7 +191,7 @@ def get_statistics():
212
  except Exception as e:
213
  return f"❌ Erro ao carregar estatísticas: {str(e)}"
214
 
215
- # Função para obter lista de dispositivos
216
  def get_device_list():
217
  try:
218
  conn = sqlite3.connect('locations.db', check_same_thread=False)
@@ -235,29 +214,35 @@ def get_device_list():
235
  conn.close()
236
 
237
  if df.empty:
238
- return "Nenhum dispositivo encontrado nos últimos 7 dias."
 
 
 
 
 
 
 
 
239
 
240
- # Filtrar apenas a localização mais recente de cada dispositivo
241
  df_latest = df[df['rn'] == 1].copy()
242
 
243
- # Adicionar coluna de status
244
  df_latest['status'] = df_latest['timestamp'].apply(
245
  lambda x: '🟢 Online' if (datetime.now() - datetime.strptime(x, '%Y-%m-%d %H:%M:%S')).total_seconds() < 300 else '🔴 Offline'
246
  )
247
 
248
- # Formatar coordenadas
249
  df_latest['coordenadas'] = df_latest.apply(
250
  lambda row: f"{row['latitude']:.6f}, {row['longitude']:.6f}", axis=1
251
  )
252
 
253
- # Selecionar colunas para exibição
254
  display_df = df_latest[['device_name', 'device_id', 'status', 'coordenadas', 'timestamp', 'battery_level', 'accuracy']].copy()
255
  display_df.columns = ['Nome', 'ID', 'Status', 'Coordenadas', 'Última Atualização', 'Bateria (%)', 'Precisão (m)']
256
 
257
  return display_df
258
 
259
  except Exception as e:
260
- return f"Erro ao carregar lista de dispositivos: {str(e)}"
 
 
261
 
262
  # Função para limpeza de dados antigos
263
  def cleanup_old_data():
@@ -265,7 +250,6 @@ def cleanup_old_data():
265
  conn = sqlite3.connect('locations.db', check_same_thread=False)
266
  cursor = conn.cursor()
267
 
268
- # Remover dados com mais de 30 dias
269
  cursor.execute("DELETE FROM locations WHERE timestamp < datetime('now', '-30 days')")
270
  deleted = cursor.rowcount
271
 
@@ -287,7 +271,6 @@ def export_data():
287
  if df.empty:
288
  return None, "Nenhum dado para exportar."
289
 
290
- # Salvar como CSV
291
  filename = f"localizacoes_export_{datetime.now().strftime('%Y%m%d_%H%M%S')}.csv"
292
  df.to_csv(filename, index=False, encoding='utf-8')
293
 
@@ -310,56 +293,25 @@ def create_interface():
310
  """)
311
 
312
  with gr.Tabs():
313
- # Aba 1: Adicionar Localização
314
  with gr.TabItem("📱 Enviar Localização"):
315
  gr.Markdown("### 📡 Enviar Nova Localização")
316
 
317
  with gr.Row():
318
- device_id = gr.Textbox(
319
- label="🆔 ID do Dispositivo",
320
- placeholder="Ex: celular_joao",
321
- info="Identificador único do dispositivo"
322
- )
323
- device_name = gr.Textbox(
324
- label="📱 Nome do Dispositivo",
325
- placeholder="Ex: Celular do João",
326
- info="Nome amigável para identificação"
327
- )
328
 
329
  with gr.Row():
330
- latitude = gr.Textbox(
331
- label="🌐 Latitude",
332
- placeholder="Ex: -23.550520",
333
- info="Coordenada de latitude (GPS)"
334
- )
335
- longitude = gr.Textbox(
336
- label="🌐 Longitude",
337
- placeholder="Ex: -46.633309",
338
- info="Coordenada de longitude (GPS)"
339
- )
340
 
341
  with gr.Row():
342
- accuracy = gr.Number(
343
- label="🎯 Precisão (metros)",
344
- value=10,
345
- info="Precisão da localização em metros"
346
- )
347
- battery = gr.Slider(
348
- label="🔋 Nível da Bateria (%)",
349
- minimum=0,
350
- maximum=100,
351
- value=100,
352
- step=1
353
- )
354
 
355
  send_btn = gr.Button("📡 Enviar Localização", variant="primary", size="lg")
356
  send_result = gr.Textbox(label="Resultado", interactive=False)
357
 
358
- send_btn.click(
359
- add_location,
360
- inputs=[device_id, device_name, latitude, longitude, accuracy, battery],
361
- outputs=send_result
362
- )
363
 
364
  gr.Markdown("""
365
  **💡 Dica:** Para obter suas coordenadas atuais:
@@ -368,82 +320,36 @@ def create_interface():
368
  3. Copie as coordenadas que aparecem
369
  """)
370
 
371
- # Aba 2: Monitoramento
372
  with gr.TabItem("🗺️ Mapa em Tempo Real"):
373
  gr.Markdown("### 🌍 Visualização em Tempo Real")
374
-
375
- with gr.Row():
376
- refresh_btn = gr.Button("🔄 Atualizar Mapa", variant="secondary")
377
- auto_refresh = gr.Checkbox(label="🔄 Atualização Automática (30s)", value=True)
378
-
379
- map_html = gr.HTML(value=get_updated_map(), label="Mapa")
380
-
381
- refresh_btn.click(
382
- get_updated_map,
383
- outputs=map_html
384
- )
385
-
386
- # Auto-refresh do mapa
387
  gr.Timer(30.0, get_updated_map, [], [map_html])
388
 
389
- # Aba 3: Lista de Dispositivos
390
  with gr.TabItem("📋 Lista de Dispositivos"):
391
  gr.Markdown("### 📱 Dispositivos Monitorados")
392
-
393
  refresh_devices_btn = gr.Button("🔄 Atualizar Lista", variant="secondary")
394
- devices_table = gr.Dataframe(
395
- value=get_device_list(),
396
- label="Dispositivos Ativos",
397
- interactive=False
398
- )
399
-
400
- refresh_devices_btn.click(
401
- get_device_list,
402
- outputs=devices_table
403
- )
404
-
405
- # Auto-refresh da tabela
406
  gr.Timer(30.0, get_device_list, [], [devices_table])
407
 
408
- # Aba 4: Estatísticas
409
  with gr.TabItem("📊 Estatísticas"):
410
  gr.Markdown("### 📈 Estatísticas do Sistema")
411
-
412
  refresh_stats_btn = gr.Button("🔄 Atualizar Estatísticas", variant="secondary")
413
- stats_display = gr.Markdown(value=get_statistics())
414
-
415
- refresh_stats_btn.click(
416
- get_statistics,
417
- outputs=stats_display
418
- )
419
-
420
- # Auto-refresh das estatísticas
421
  gr.Timer(60.0, get_statistics, [], [stats_display])
422
 
423
- # Aba 5: Administração
424
  with gr.TabItem("⚙️ Administração"):
425
  gr.Markdown("### 🛠️ Ferramentas de Administração")
426
-
427
  with gr.Row():
428
  cleanup_btn = gr.Button("🧹 Limpar Dados Antigos", variant="secondary")
429
  export_btn = gr.Button("📥 Exportar Dados", variant="secondary")
430
-
431
  admin_result = gr.Textbox(label="Resultado da Operação", interactive=False)
432
  export_file = gr.File(label="Arquivo Exportado", visible=False)
433
-
434
- cleanup_btn.click(
435
- cleanup_old_data,
436
- outputs=admin_result
437
- )
438
-
439
- def handle_export():
440
- file_path, message = export_data()
441
- return message, file_path
442
-
443
- export_btn.click(
444
- handle_export,
445
- outputs=[admin_result, export_file]
446
- )
447
 
448
  gr.Markdown("""
449
  **⚠️ Informações Importantes:**
@@ -456,7 +362,6 @@ def create_interface():
456
  gr.Markdown("""
457
  ---
458
  ### 📱 Como Usar no Celular:
459
-
460
  1. **Para Enviar Localização:** Use a aba "Enviar Localização"
461
  2. **Para Monitorar:** Use a aba "Mapa em Tempo Real"
462
  3. **Atualizações:** O sistema atualiza automaticamente
 
1
  import gradio as gr
2
  import sqlite3
 
3
  import pandas as pd
4
+ from datetime import datetime
5
  import folium
6
  from folium import plugins
 
 
 
 
7
 
8
  # Configuração do banco de dados
9
  def init_db():
 
62
  try:
63
  conn = sqlite3.connect('locations.db', check_same_thread=False)
64
 
 
65
  query = '''
66
  SELECT device_id, device_name, latitude, longitude,
67
  timestamp, accuracy, battery_level,
 
71
  '''
72
 
73
  df = pd.read_sql_query(query, conn)
74
+ df_latest = df[df['rn'] == 1].copy()
75
 
76
  conn.close()
77
 
78
  if df_latest.empty:
 
79
  m = folium.Map(location=[-14.235, -51.9253], zoom_start=4)
80
  folium.Marker(
81
  [-14.235, -51.9253],
 
84
  ).add_to(m)
85
  return m._repr_html_()
86
 
 
87
  center_lat = df_latest['latitude'].mean()
88
  center_lng = df_latest['longitude'].mean()
89
  m = folium.Map(location=[center_lat, center_lng], zoom_start=12)
90
 
 
91
  colors = ['red', 'blue', 'green', 'purple', 'orange', 'darkred', 'lightred',
92
  'beige', 'darkblue', 'darkgreen', 'cadetblue', 'darkpurple', 'white', 'pink', 'lightblue', 'lightgreen', 'gray', 'black', 'lightgray']
93
 
94
  for idx, row in df_latest.iterrows():
 
95
  last_update = datetime.strptime(row['timestamp'], '%Y-%m-%d %H:%M:%S')
96
+ is_online = (datetime.now() - last_update).total_seconds() < 300
97
 
 
98
  color = colors[idx % len(colors)]
99
  icon_color = 'green' if is_online else 'red'
100
 
 
101
  popup_html = f"""
102
  <div style="font-family: Arial; width: 200px;">
103
  <h4>📱 {row['device_name']}</h4>
 
118
  icon=folium.Icon(color=icon_color, icon='phone', prefix='fa')
119
  ).add_to(m)
120
 
 
121
  folium.Circle(
122
  [row['latitude'], row['longitude']],
123
  radius=row['accuracy'],
 
128
  weight=1
129
  ).add_to(m)
130
 
 
131
  for device_id in df_latest['device_id'].unique():
132
  device_history = df[df['device_id'] == device_id].sort_values('timestamp')
133
  if len(device_history) > 1:
 
140
  popup=f"Trajeto: {device_history.iloc[0]['device_name']}"
141
  ).add_to(m)
142
 
 
143
  plugins.Fullscreen().add_to(m)
 
 
144
  minimap = plugins.MiniMap()
145
  m.add_child(minimap)
146
 
 
153
  def get_statistics():
154
  try:
155
  conn = sqlite3.connect('locations.db', check_same_thread=False)
 
 
156
  cursor = conn.cursor()
157
+
158
  cursor.execute("SELECT COUNT(DISTINCT device_id) FROM locations")
159
  total_devices = cursor.fetchone()[0]
160
 
 
161
  cursor.execute("SELECT COUNT(*) FROM locations WHERE timestamp > datetime('now', '-1 day')")
162
  locations_24h = cursor.fetchone()[0]
163
 
 
164
  cursor.execute("""
165
  SELECT COUNT(DISTINCT device_id) FROM locations
166
  WHERE timestamp > datetime('now', '-5 minutes')
167
  """)
168
  online_devices = cursor.fetchone()[0]
169
 
 
170
  cursor.execute("SELECT MAX(timestamp) FROM locations")
171
  last_update = cursor.fetchone()[0]
172
 
 
191
  except Exception as e:
192
  return f"❌ Erro ao carregar estatísticas: {str(e)}"
193
 
194
+ # Função para obter lista de dispositivos (modificada para sempre retornar DataFrame)
195
  def get_device_list():
196
  try:
197
  conn = sqlite3.connect('locations.db', check_same_thread=False)
 
214
  conn.close()
215
 
216
  if df.empty:
217
+ return pd.DataFrame([{
218
+ "Nome": "Nenhum dispositivo encontrado",
219
+ "ID": "",
220
+ "Status": "",
221
+ "Coordenadas": "",
222
+ "Última Atualização": "",
223
+ "Bateria (%)": "",
224
+ "Precisão (m)": ""
225
+ }])
226
 
 
227
  df_latest = df[df['rn'] == 1].copy()
228
 
 
229
  df_latest['status'] = df_latest['timestamp'].apply(
230
  lambda x: '🟢 Online' if (datetime.now() - datetime.strptime(x, '%Y-%m-%d %H:%M:%S')).total_seconds() < 300 else '🔴 Offline'
231
  )
232
 
 
233
  df_latest['coordenadas'] = df_latest.apply(
234
  lambda row: f"{row['latitude']:.6f}, {row['longitude']:.6f}", axis=1
235
  )
236
 
 
237
  display_df = df_latest[['device_name', 'device_id', 'status', 'coordenadas', 'timestamp', 'battery_level', 'accuracy']].copy()
238
  display_df.columns = ['Nome', 'ID', 'Status', 'Coordenadas', 'Última Atualização', 'Bateria (%)', 'Precisão (m)']
239
 
240
  return display_df
241
 
242
  except Exception as e:
243
+ return pd.DataFrame([{
244
+ "Erro": f"Erro ao carregar lista de dispositivos: {str(e)}"
245
+ }])
246
 
247
  # Função para limpeza de dados antigos
248
  def cleanup_old_data():
 
250
  conn = sqlite3.connect('locations.db', check_same_thread=False)
251
  cursor = conn.cursor()
252
 
 
253
  cursor.execute("DELETE FROM locations WHERE timestamp < datetime('now', '-30 days')")
254
  deleted = cursor.rowcount
255
 
 
271
  if df.empty:
272
  return None, "Nenhum dado para exportar."
273
 
 
274
  filename = f"localizacoes_export_{datetime.now().strftime('%Y%m%d_%H%M%S')}.csv"
275
  df.to_csv(filename, index=False, encoding='utf-8')
276
 
 
293
  """)
294
 
295
  with gr.Tabs():
 
296
  with gr.TabItem("📱 Enviar Localização"):
297
  gr.Markdown("### 📡 Enviar Nova Localização")
298
 
299
  with gr.Row():
300
+ device_id = gr.Textbox(label="🆔 ID do Dispositivo", placeholder="Ex: celular_joao")
301
+ device_name = gr.Textbox(label="📱 Nome do Dispositivo", placeholder="Ex: Celular do João")
 
 
 
 
 
 
 
 
302
 
303
  with gr.Row():
304
+ latitude = gr.Textbox(label="🌐 Latitude", placeholder="Ex: -23.550520")
305
+ longitude = gr.Textbox(label="🌐 Longitude", placeholder="Ex: -46.633309")
 
 
 
 
 
 
 
 
306
 
307
  with gr.Row():
308
+ accuracy = gr.Number(label="🎯 Precisão (metros)", value=10)
309
+ battery = gr.Slider(label="🔋 Nível da Bateria (%)", minimum=0, maximum=100, value=100, step=1)
 
 
 
 
 
 
 
 
 
 
310
 
311
  send_btn = gr.Button("📡 Enviar Localização", variant="primary", size="lg")
312
  send_result = gr.Textbox(label="Resultado", interactive=False)
313
 
314
+ send_btn.click(add_location, inputs=[device_id, device_name, latitude, longitude, accuracy, battery], outputs=send_result)
 
 
 
 
315
 
316
  gr.Markdown("""
317
  **💡 Dica:** Para obter suas coordenadas atuais:
 
320
  3. Copie as coordenadas que aparecem
321
  """)
322
 
 
323
  with gr.TabItem("🗺️ Mapa em Tempo Real"):
324
  gr.Markdown("### 🌍 Visualização em Tempo Real")
325
+ refresh_btn = gr.Button("🔄 Atualizar Mapa", variant="secondary")
326
+ map_html = gr.HTML(label="Mapa")
327
+ refresh_btn.click(get_updated_map, outputs=map_html)
 
 
 
 
 
 
 
 
 
 
328
  gr.Timer(30.0, get_updated_map, [], [map_html])
329
 
 
330
  with gr.TabItem("📋 Lista de Dispositivos"):
331
  gr.Markdown("### 📱 Dispositivos Monitorados")
 
332
  refresh_devices_btn = gr.Button("🔄 Atualizar Lista", variant="secondary")
333
+ devices_table = gr.Dataframe(label="Dispositivos Ativos", interactive=False)
334
+ refresh_devices_btn.click(get_device_list, outputs=devices_table)
 
 
 
 
 
 
 
 
 
 
335
  gr.Timer(30.0, get_device_list, [], [devices_table])
336
 
 
337
  with gr.TabItem("📊 Estatísticas"):
338
  gr.Markdown("### 📈 Estatísticas do Sistema")
 
339
  refresh_stats_btn = gr.Button("🔄 Atualizar Estatísticas", variant="secondary")
340
+ stats_display = gr.Markdown()
341
+ refresh_stats_btn.click(get_statistics, outputs=stats_display)
 
 
 
 
 
 
342
  gr.Timer(60.0, get_statistics, [], [stats_display])
343
 
 
344
  with gr.TabItem("⚙️ Administração"):
345
  gr.Markdown("### 🛠️ Ferramentas de Administração")
 
346
  with gr.Row():
347
  cleanup_btn = gr.Button("🧹 Limpar Dados Antigos", variant="secondary")
348
  export_btn = gr.Button("📥 Exportar Dados", variant="secondary")
 
349
  admin_result = gr.Textbox(label="Resultado da Operação", interactive=False)
350
  export_file = gr.File(label="Arquivo Exportado", visible=False)
351
+ cleanup_btn.click(cleanup_old_data, outputs=admin_result)
352
+ export_btn.click(export_data, outputs=[admin_result, export_file])
 
 
 
 
 
 
 
 
 
 
 
 
353
 
354
  gr.Markdown("""
355
  **⚠️ Informações Importantes:**
 
362
  gr.Markdown("""
363
  ---
364
  ### 📱 Como Usar no Celular:
 
365
  1. **Para Enviar Localização:** Use a aba "Enviar Localização"
366
  2. **Para Monitorar:** Use a aba "Mapa em Tempo Real"
367
  3. **Atualizações:** O sistema atualiza automaticamente