leonett commited on
Commit
b7c0e2d
·
verified ·
1 Parent(s): 9174adf

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +30 -25
app.py CHANGED
@@ -7,13 +7,13 @@ import re
7
  import os
8
  import tempfile
9
  import base64
10
- from fpdf import FPDF, HTMLMixin # Estos módulos ya no se usan en este ejemplo
11
 
12
  # ---------------- Funciones de análisis y grafo -------------------
13
 
14
  def get_transaction(tx_id):
15
  """
16
- Obtiene datos de una transacción Bitcoin usando endpoints públicos.
17
  Se prueba primero con Blockstream.info y, de fallar, con mempool.space.
18
  """
19
  urls = [
@@ -71,7 +71,7 @@ def check_blockchain_tags(tx_id):
71
  """
72
  Consulta la API pública de blockchain.com para ver si el TXID (o sus metadatos)
73
  indica que la transacción ha sido etiquetada como MIXER.
74
- (Esta función es un ejemplo y puede requerir ajustes según la respuesta real.)
75
  """
76
  url = f"https://blockchain.info/rawtx/{tx_id}?format=json"
77
  try:
@@ -96,14 +96,13 @@ def analizar_transaccion(tx_id):
96
  - Calcula totales en BTC y fee, mostrando también su equivalente en USD.
97
  - Muestra información adicional (versión, tamaño, peso, fee rate).
98
  - Aplica heurística para detectar posibles CoinJoin/mixers.
99
- - Incorpora información de blockchain.com (etiqueta MIXER).
100
  - Genera un grafo interactivo.
101
- - Retorna un informe en HTML, la figura del grafo y una tupla (reporte, fig) que se guarda en el estado.
102
  """
103
  tx_data = get_transaction(tx_id)
104
  if not tx_data:
105
  return ("❌ Transacción no encontrada o error al obtener datos. Asegúrate de ingresar un TXID válido."), None, None
106
-
107
  try:
108
  num_inputs = len(tx_data.get("vin", []))
109
  num_outputs = len(tx_data.get("vout", []))
@@ -113,7 +112,6 @@ def analizar_transaccion(tx_id):
113
  total_output_value = sum(out.get("value", 0) for out in tx_data.get("vout", [])) / 1e8
114
  fee = total_input_value - total_output_value
115
 
116
- # Heurística para detectar mixer
117
  heuristic_mixer = ((num_inputs > 5 and num_outputs > 5 and montos_unicos < 3) or
118
  (num_outputs > 2 and montos_unicos <= 2))
119
  es_mixer_blockchain = check_blockchain_tags(tx_id)
@@ -247,23 +245,35 @@ def analizar_transaccion(tx_id):
247
  </p>
248
  </div>
249
  """
250
- # Se devuelve además la tupla (reporte, fig) para almacenarla en el estado.
251
  return reporte, fig, (reporte, fig)
252
 
253
  except Exception as e:
254
  return f"⚠️ Error durante el análisis: {str(e)}", None, None
255
 
256
- # ---------------- Función para mostrar el modal -------------------
257
 
258
  def mostrar_modal(analysis_tuple):
259
  """
260
- Función que, a partir de la tupla de análisis, devuelve la actualización para
261
- abrir el modal y el contenido HTML del informe.
262
  """
263
  if not analysis_tuple:
264
- return gr.update(visible=False), "<p>No hay análisis generado.</p>"
265
  report, _ = analysis_tuple
266
- return gr.update(visible=True), report
 
 
 
 
 
 
 
 
 
 
 
 
 
 
267
 
268
  # ---------------- INTERFAZ GRÁFICA CON GRADIO -------------------
269
 
@@ -278,7 +288,7 @@ with gr.Blocks(
278
  gr.Markdown("**Nota:** Este analizador funciona únicamente con transacciones de Bitcoin. No se pueden analizar transacciones de Ethereum.")
279
 
280
  with gr.Row():
281
- # Columna izquierda: TXID, Ejemplos y Explicación
282
  with gr.Column(scale=1):
283
  tx_input = gr.Textbox(
284
  label="TXID de la Transacción",
@@ -292,7 +302,6 @@ with gr.Blocks(
292
  ],
293
  inputs=tx_input
294
  )
295
- # Recuadro de explicación (scroll ampliado a 350px)
296
  explanation_box = gr.HTML(value="""
297
  <div style="overflow-y: auto; height: 350px; border: 1px solid #cccccc; padding: 10px;">
298
  <h4>Explicación de los campos:</h4>
@@ -315,24 +324,20 @@ with gr.Blocks(
315
  </ul>
316
  </div>
317
  """)
318
- # Columna derecha: Grafo y Reporte
319
  with gr.Column(scale=1):
320
  plot_output = gr.Plot()
321
  reporte_html = gr.HTML()
322
  analyze_btn = gr.Button("Analizar Transacción", elem_classes=["custom-btn"])
 
 
323
 
324
  # Estado para almacenar el análisis (tupla: (reporte, fig))
325
  analysis_state = gr.State()
326
 
327
- # Al hacer clic en "Analizar Transacción", se actualizan el reporte, el grafo y se guarda el análisis en el estado.
328
  analyze_btn.click(fn=analizar_transaccion, inputs=tx_input, outputs=[reporte_html, plot_output, analysis_state])
329
-
330
- # Botón para generar el análisis en un modal emergente.
331
- modal_btn = gr.Button("GENERAR ANALISIS", elem_classes=["custom-btn"])
332
- with gr.Modal("Resultados del Análisis", visible=False) as result_modal:
333
- modal_report = gr.HTML()
334
-
335
- # La función mostrar_modal abrirá el modal con el contenido del análisis.
336
- modal_btn.click(fn=mostrar_modal, inputs=analysis_state, outputs=[result_modal, modal_report])
337
 
338
  demo.launch()
 
7
  import os
8
  import tempfile
9
  import base64
10
+ # No se usan fpdf en este ejemplo
11
 
12
  # ---------------- Funciones de análisis y grafo -------------------
13
 
14
  def get_transaction(tx_id):
15
  """
16
+ Obtiene los datos de una transacción Bitcoin usando endpoints públicos.
17
  Se prueba primero con Blockstream.info y, de fallar, con mempool.space.
18
  """
19
  urls = [
 
71
  """
72
  Consulta la API pública de blockchain.com para ver si el TXID (o sus metadatos)
73
  indica que la transacción ha sido etiquetada como MIXER.
74
+ (Esta función es un ejemplo y podría necesitar ajustes según la respuesta real.)
75
  """
76
  url = f"https://blockchain.info/rawtx/{tx_id}?format=json"
77
  try:
 
96
  - Calcula totales en BTC y fee, mostrando también su equivalente en USD.
97
  - Muestra información adicional (versión, tamaño, peso, fee rate).
98
  - Aplica heurística para detectar posibles CoinJoin/mixers.
99
+ - Incorpora información adicional de blockchain.com (etiqueta MIXER).
100
  - Genera un grafo interactivo.
101
+ - Retorna un informe en HTML, la figura del grafo y una tupla (reporte, fig) para su uso.
102
  """
103
  tx_data = get_transaction(tx_id)
104
  if not tx_data:
105
  return ("❌ Transacción no encontrada o error al obtener datos. Asegúrate de ingresar un TXID válido."), None, None
 
106
  try:
107
  num_inputs = len(tx_data.get("vin", []))
108
  num_outputs = len(tx_data.get("vout", []))
 
112
  total_output_value = sum(out.get("value", 0) for out in tx_data.get("vout", [])) / 1e8
113
  fee = total_input_value - total_output_value
114
 
 
115
  heuristic_mixer = ((num_inputs > 5 and num_outputs > 5 and montos_unicos < 3) or
116
  (num_outputs > 2 and montos_unicos <= 2))
117
  es_mixer_blockchain = check_blockchain_tags(tx_id)
 
245
  </p>
246
  </div>
247
  """
 
248
  return reporte, fig, (reporte, fig)
249
 
250
  except Exception as e:
251
  return f"⚠️ Error durante el análisis: {str(e)}", None, None
252
 
253
+ # ---------------- Función para mostrar el modal mediante HTML -------------------
254
 
255
  def mostrar_modal(analysis_tuple):
256
  """
257
+ A partir de la tupla de análisis, devuelve un HTML con un modal emergente que contiene el informe.
 
258
  """
259
  if not analysis_tuple:
260
+ return "<p>No hay análisis generado.</p>"
261
  report, _ = analysis_tuple
262
+ html_modal = f'''
263
+ <div id="myModal" style="
264
+ position: fixed; top: 0; left: 0; width: 100%; height: 100%;
265
+ background: rgba(0,0,0,0.8); z-index: 9999;">
266
+ <div style="
267
+ position: absolute; top: 50%; left: 50%;
268
+ transform: translate(-50%, -50%);
269
+ background: white; padding: 20px; max-height: 90%; overflow-y: auto;">
270
+ {report}
271
+ <br><br><button onclick="document.getElementById('myModal').remove();"
272
+ style='padding: 5px 10px; font-size: 12px;'>Cerrar</button>
273
+ </div>
274
+ </div>
275
+ '''
276
+ return html_modal
277
 
278
  # ---------------- INTERFAZ GRÁFICA CON GRADIO -------------------
279
 
 
288
  gr.Markdown("**Nota:** Este analizador funciona únicamente con transacciones de Bitcoin. No se pueden analizar transacciones de Ethereum.")
289
 
290
  with gr.Row():
291
+ # Columna izquierda: Campo de TXID, Ejemplos y Explicación de campos
292
  with gr.Column(scale=1):
293
  tx_input = gr.Textbox(
294
  label="TXID de la Transacción",
 
302
  ],
303
  inputs=tx_input
304
  )
 
305
  explanation_box = gr.HTML(value="""
306
  <div style="overflow-y: auto; height: 350px; border: 1px solid #cccccc; padding: 10px;">
307
  <h4>Explicación de los campos:</h4>
 
324
  </ul>
325
  </div>
326
  """)
327
+ # Columna derecha: Grafo, Reporte y botón para mostrar modal con análisis completo
328
  with gr.Column(scale=1):
329
  plot_output = gr.Plot()
330
  reporte_html = gr.HTML()
331
  analyze_btn = gr.Button("Analizar Transacción", elem_classes=["custom-btn"])
332
+ modal_btn = gr.Button("GENERAR ANALISIS", elem_classes=["custom-btn"])
333
+ modal_output = gr.HTML()
334
 
335
  # Estado para almacenar el análisis (tupla: (reporte, fig))
336
  analysis_state = gr.State()
337
 
338
+ # Al hacer clic en "Analizar Transacción", se generan reporte, grafo y se guarda el análisis
339
  analyze_btn.click(fn=analizar_transaccion, inputs=tx_input, outputs=[reporte_html, plot_output, analysis_state])
340
+ # Al hacer clic en "GENERAR ANALISIS", se muestra un modal emergente con el informe completo
341
+ modal_btn.click(fn=mostrar_modal, inputs=analysis_state, outputs=modal_output)
 
 
 
 
 
 
342
 
343
  demo.launch()