Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
@@ -7,7 +7,6 @@ import re
|
|
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 |
|
@@ -120,23 +119,19 @@ def analizar_transaccion(tx_id):
|
|
120 |
if es_mixer:
|
121 |
if heuristic_mixer and es_mixer_blockchain:
|
122 |
mixer_message = (
|
123 |
-
"<p style='color: #FF5252;'><strong>Alerta de Mixer / CoinJoin:</strong> "
|
124 |
-
"La transacci贸n cumple criterios heur铆sticos y la API de blockchain.com la etiqueta como MIXER.</p>"
|
125 |
)
|
126 |
elif heuristic_mixer:
|
127 |
mixer_message = (
|
128 |
-
"<p style='color: #FF5252;'><strong>Alerta de Mixer / CoinJoin:</strong> "
|
129 |
-
"La transacci贸n cumple criterios heur铆sticos compatibles con un mixer.</p>"
|
130 |
)
|
131 |
elif es_mixer_blockchain:
|
132 |
mixer_message = (
|
133 |
-
"<p style='color: #FF5252;'><strong>Alerta de Mixer / CoinJoin:</strong> "
|
134 |
-
"La API de blockchain.com etiqueta esta transacci贸n como MIXER.</p>"
|
135 |
)
|
136 |
else:
|
137 |
mixer_message = (
|
138 |
-
"<p style='color: #4CAF50;'><strong>Sin indicios de mezcla:</strong> "
|
139 |
-
"La transacci贸n no presenta patrones de mixer.</p>"
|
140 |
)
|
141 |
|
142 |
btc_price = get_btc_price() or 0
|
@@ -221,6 +216,7 @@ def analizar_transaccion(tx_id):
|
|
221 |
fee_str = f"{fee:.8f} BTC"
|
222 |
fee_str += f" (${fee * btc_price:,.2f})" if btc_price else ""
|
223 |
|
|
|
224 |
reporte = f"""
|
225 |
<div style="padding: 20px; border-radius: 10px;">
|
226 |
<h3 style="color: {'#FF5252' if es_mixer else '#4CAF50'};">
|
@@ -232,13 +228,12 @@ def analizar_transaccion(tx_id):
|
|
232 |
<p><strong>Tama帽o:</strong> {size if size else 'N/A'} bytes</p>
|
233 |
<p><strong>Peso:</strong> {weight}</p>
|
234 |
<p><strong>Fee rate:</strong> {fee_rate_str}</p>
|
235 |
-
<hr>
|
236 |
<p>馃摜 <strong>Inputs:</strong> {num_inputs}</p>
|
237 |
{mixer_metrics}
|
238 |
-
<p
|
239 |
-
<p
|
240 |
-
<p
|
241 |
-
<p
|
242 |
{mixer_message}
|
243 |
<p style="font-size: 0.9em;">
|
244 |
Nota: La detecci贸n se basa en heur铆sticas y en informaci贸n adicional de blockchain.com. Se recomienda usar herramientas especializadas para un an谩lisis forense completo.
|
@@ -250,25 +245,23 @@ def analizar_transaccion(tx_id):
|
|
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
|
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="
|
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:
|
268 |
-
|
269 |
-
background: white; padding: 20px; max-height: 90%; overflow-y: auto;">
|
270 |
{report}
|
271 |
-
<br><br
|
|
|
272 |
style='padding: 5px 10px; font-size: 12px;'>Cerrar</button>
|
273 |
</div>
|
274 |
</div>
|
@@ -288,12 +281,13 @@ with gr.Blocks(
|
|
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,
|
292 |
with gr.Column(scale=1):
|
293 |
tx_input = gr.Textbox(
|
294 |
label="TXID de la Transacci贸n",
|
295 |
placeholder="Ej: 9dd51e2d45f4f7bddcc3f0f7a05c3fd60543a11cfc9fbd0e1ca4434668cfa3e1"
|
296 |
)
|
|
|
297 |
gr.Markdown("### Ejemplos de TXIDs v谩lidos:")
|
298 |
gr.Examples(
|
299 |
examples=[
|
@@ -328,16 +322,15 @@ with gr.Blocks(
|
|
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
|
339 |
analyze_btn.click(fn=analizar_transaccion, inputs=tx_input, outputs=[reporte_html, plot_output, analysis_state])
|
340 |
-
# Al
|
341 |
modal_btn.click(fn=mostrar_modal, inputs=analysis_state, outputs=modal_output)
|
342 |
|
343 |
-
demo.launch()
|
|
|
7 |
import os
|
8 |
import tempfile
|
9 |
import base64
|
|
|
10 |
|
11 |
# ---------------- Funciones de an谩lisis y grafo -------------------
|
12 |
|
|
|
119 |
if es_mixer:
|
120 |
if heuristic_mixer and es_mixer_blockchain:
|
121 |
mixer_message = (
|
122 |
+
"<p style='color: #FF5252;'><strong>Alerta de Mixer / CoinJoin:</strong> La transacci贸n cumple criterios heur铆sticos y la API de blockchain.com la etiqueta como MIXER.</p>"
|
|
|
123 |
)
|
124 |
elif heuristic_mixer:
|
125 |
mixer_message = (
|
126 |
+
"<p style='color: #FF5252;'><strong>Alerta de Mixer / CoinJoin:</strong> La transacci贸n cumple criterios heur铆sticos compatibles con un mixer.</p>"
|
|
|
127 |
)
|
128 |
elif es_mixer_blockchain:
|
129 |
mixer_message = (
|
130 |
+
"<p style='color: #FF5252;'><strong>Alerta de Mixer / CoinJoin:</strong> La API de blockchain.com etiqueta esta transacci贸n como MIXER.</p>"
|
|
|
131 |
)
|
132 |
else:
|
133 |
mixer_message = (
|
134 |
+
"<p style='color: #4CAF50;'><strong>Sin indicios de mezcla:</strong> La transacci贸n no presenta patrones de mixer.</p>"
|
|
|
135 |
)
|
136 |
|
137 |
btc_price = get_btc_price() or 0
|
|
|
216 |
fee_str = f"{fee:.8f} BTC"
|
217 |
fee_str += f" (${fee * btc_price:,.2f})" if btc_price else ""
|
218 |
|
219 |
+
# Se ha eliminado el <hr> para que la informaci贸n aparezca de forma continua.
|
220 |
reporte = f"""
|
221 |
<div style="padding: 20px; border-radius: 10px;">
|
222 |
<h3 style="color: {'#FF5252' if es_mixer else '#4CAF50'};">
|
|
|
228 |
<p><strong>Tama帽o:</strong> {size if size else 'N/A'} bytes</p>
|
229 |
<p><strong>Peso:</strong> {weight}</p>
|
230 |
<p><strong>Fee rate:</strong> {fee_rate_str}</p>
|
|
|
231 |
<p>馃摜 <strong>Inputs:</strong> {num_inputs}</p>
|
232 |
{mixer_metrics}
|
233 |
+
<p><strong>Total Entradas:</strong> {total_input_str}</p>
|
234 |
+
<p><strong>Total Salidas:</strong> {total_output_str}</p>
|
235 |
+
<p><strong>Fee:</strong> {fee_str}</p>
|
236 |
+
<p><strong>Estado de Confirmaci贸n:</strong> {"Confirmada" if status.get("confirmed", False) else "No confirmada"}</p>
|
237 |
{mixer_message}
|
238 |
<p style="font-size: 0.9em;">
|
239 |
Nota: La detecci贸n se basa en heur铆sticas y en informaci贸n adicional de blockchain.com. Se recomienda usar herramientas especializadas para un an谩lisis forense completo.
|
|
|
245 |
except Exception as e:
|
246 |
return f"鈿狅笍 Error durante el an谩lisis: {str(e)}", None, None
|
247 |
|
|
|
|
|
248 |
def mostrar_modal(analysis_tuple):
|
249 |
"""
|
250 |
+
A partir de la tupla de an谩lisis, devuelve un HTML que simula un modal emergente con el informe completo.
|
251 |
"""
|
252 |
if not analysis_tuple:
|
253 |
return "<p>No hay an谩lisis generado.</p>"
|
254 |
report, _ = analysis_tuple
|
255 |
html_modal = f'''
|
256 |
+
<div id="modalOverlay" style="
|
257 |
position: fixed; top: 0; left: 0; width: 100%; height: 100%;
|
258 |
+
background: rgba(0,0,0,0.8); z-index: 9999; overflow: auto;">
|
259 |
<div style="
|
260 |
+
position: relative; margin: 5% auto; padding: 20px;
|
261 |
+
background: inherit; max-width: 800px; border-radius: 10px;">
|
|
|
262 |
{report}
|
263 |
+
<br><br>
|
264 |
+
<button onclick="document.getElementById('modalOverlay').remove();"
|
265 |
style='padding: 5px 10px; font-size: 12px;'>Cerrar</button>
|
266 |
</div>
|
267 |
</div>
|
|
|
281 |
gr.Markdown("**Nota:** Este analizador funciona 煤nicamente con transacciones de Bitcoin. No se pueden analizar transacciones de Ethereum.")
|
282 |
|
283 |
with gr.Row():
|
284 |
+
# Columna izquierda: Campo de TXID, ejemplos y explicaci贸n de campos
|
285 |
with gr.Column(scale=1):
|
286 |
tx_input = gr.Textbox(
|
287 |
label="TXID de la Transacci贸n",
|
288 |
placeholder="Ej: 9dd51e2d45f4f7bddcc3f0f7a05c3fd60543a11cfc9fbd0e1ca4434668cfa3e1"
|
289 |
)
|
290 |
+
analyze_btn = gr.Button("Analizar Transacci贸n", elem_classes=["custom-btn"])
|
291 |
gr.Markdown("### Ejemplos de TXIDs v谩lidos:")
|
292 |
gr.Examples(
|
293 |
examples=[
|
|
|
322 |
with gr.Column(scale=1):
|
323 |
plot_output = gr.Plot()
|
324 |
reporte_html = gr.HTML()
|
|
|
325 |
modal_btn = gr.Button("GENERAR ANALISIS", elem_classes=["custom-btn"])
|
326 |
modal_output = gr.HTML()
|
327 |
|
328 |
# Estado para almacenar el an谩lisis (tupla: (reporte, fig))
|
329 |
analysis_state = gr.State()
|
330 |
|
331 |
+
# Al pulsar "Analizar Transacci贸n", se generan reporte, grafo y se guarda el an谩lisis.
|
332 |
analyze_btn.click(fn=analizar_transaccion, inputs=tx_input, outputs=[reporte_html, plot_output, analysis_state])
|
333 |
+
# Al pulsar "GENERAR ANALISIS", se muestra un modal emergente con el informe completo.
|
334 |
modal_btn.click(fn=mostrar_modal, inputs=analysis_state, outputs=modal_output)
|
335 |
|
336 |
+
demo.launch()
|