Spaces:
Running
Running
Update app.py
Browse files
app.py
CHANGED
|
@@ -281,7 +281,7 @@ def visualize_logprobs(json_input, chunk=0, chunk_size=100):
|
|
| 281 |
logger.error("Visualization failed: %s (Input: %s)", str(e), json_input[:100] + "..." if len(json_input) > 100 else json_input)
|
| 282 |
return (create_empty_figure("Log Probabilities of Generated Tokens"), None, "No finite log probabilities to display.", create_empty_figure("Top Token Log Probabilities"), create_empty_figure("Significant Probability Drops"), 1, 0)
|
| 283 |
|
| 284 |
-
# Analysis functions for detecting correct vs. incorrect traces (unchanged
|
| 285 |
def analyze_confidence_signature(logprobs, tokens):
|
| 286 |
if not logprobs or not tokens:
|
| 287 |
return "No data for confidence signature analysis.", None
|
|
@@ -476,114 +476,120 @@ def analyze_full_trace(json_input):
|
|
| 476 |
return analysis_html, None, None, None, None, None
|
| 477 |
|
| 478 |
# Gradio interface with two tabs: Trace Analysis and Visualization
|
| 479 |
-
|
| 480 |
-
gr.
|
| 481 |
-
|
| 482 |
-
|
| 483 |
-
|
|
|
|
| 484 |
|
| 485 |
-
|
| 486 |
-
|
| 487 |
-
|
| 488 |
-
|
| 489 |
-
|
| 490 |
-
|
| 491 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 492 |
)
|
| 493 |
-
with gr.Row():
|
| 494 |
-
analysis_output = gr.HTML(label="Trace Analysis Results")
|
| 495 |
-
|
| 496 |
-
btn_analyze = gr.Button("Analyze Trace")
|
| 497 |
-
btn_analyze.click(
|
| 498 |
-
fn=analyze_full_trace,
|
| 499 |
-
inputs=[json_input_analysis],
|
| 500 |
-
outputs=[analysis_output, gr.State(), gr.State(), gr.State(), gr.State(), gr.State()],
|
| 501 |
-
)
|
| 502 |
|
| 503 |
-
|
| 504 |
-
|
| 505 |
-
|
| 506 |
-
|
| 507 |
-
|
| 508 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 509 |
)
|
| 510 |
-
chunk = gr.Number(value=0, label="Current Chunk", precision=0, minimum=0)
|
| 511 |
-
|
| 512 |
-
with gr.Row():
|
| 513 |
-
plot_output = gr.Plot(label="Log Probability Plot (Click for Tokens)")
|
| 514 |
-
drops_output = gr.Plot(label="Probability Drops (Click for Details)")
|
| 515 |
-
|
| 516 |
-
with gr.Row():
|
| 517 |
-
table_output = gr.Dataframe(label="Token Log Probabilities and Top Alternatives")
|
| 518 |
-
alt_viz_output = gr.Plot(label="Top Token Log Probabilities (Click for Details)")
|
| 519 |
|
| 520 |
-
|
| 521 |
-
|
| 522 |
-
|
| 523 |
-
|
| 524 |
-
|
| 525 |
-
|
| 526 |
-
|
| 527 |
-
|
| 528 |
-
|
| 529 |
-
|
| 530 |
-
|
| 531 |
-
|
| 532 |
-
|
| 533 |
-
|
| 534 |
-
|
| 535 |
-
|
| 536 |
-
|
| 537 |
-
|
| 538 |
-
|
| 539 |
-
|
| 540 |
-
|
| 541 |
-
|
| 542 |
-
|
| 543 |
-
|
| 544 |
-
|
| 545 |
-
|
| 546 |
-
|
| 547 |
-
|
| 548 |
-
|
| 549 |
-
|
| 550 |
-
|
| 551 |
-
|
| 552 |
-
|
| 553 |
-
current_chunk += 1
|
| 554 |
-
# If precomputed next chunk exists, use it; otherwise, compute it
|
| 555 |
-
if precomputed_next:
|
| 556 |
-
next_tokens, next_logprobs, next_alternatives = precomputed_next
|
| 557 |
-
if next_tokens and next_logprobs and next_alternatives:
|
| 558 |
-
logger.debug("Using precomputed next chunk for chunk %d", current_chunk)
|
| 559 |
-
return visualize_logprobs(json_input, current_chunk)
|
| 560 |
-
return visualize_logprobs(json_input, current_chunk)
|
| 561 |
-
|
| 562 |
-
prev_btn.click(
|
| 563 |
-
fn=update_chunk,
|
| 564 |
-
inputs=[json_input_viz, chunk, gr.State(value="prev"), precomputed_next],
|
| 565 |
-
outputs=[plot_output, table_output, text_output, alt_viz_output, drops_output, total_chunks_output, chunk],
|
| 566 |
-
)
|
| 567 |
-
|
| 568 |
-
next_btn.click(
|
| 569 |
-
fn=update_chunk,
|
| 570 |
-
inputs=[json_input_viz, chunk, gr.State(value="next"), precomputed_next],
|
| 571 |
-
outputs=[plot_output, table_output, text_output, alt_viz_output, drops_output, total_chunks_output, chunk],
|
| 572 |
-
)
|
| 573 |
|
| 574 |
-
|
| 575 |
-
|
| 576 |
-
|
| 577 |
-
|
| 578 |
-
|
| 579 |
-
logger.error("Precomputation trigger failed: %s", str(e))
|
| 580 |
-
return gr.update(value=current_chunk)
|
| 581 |
-
|
| 582 |
-
# Use a dummy event to trigger precomputation on chunk change (simplified for Gradio)
|
| 583 |
-
chunk.change(
|
| 584 |
-
fn=trigger_precomputation,
|
| 585 |
-
inputs=[json_input_viz, chunk],
|
| 586 |
-
outputs=[chunk],
|
| 587 |
-
)
|
| 588 |
|
| 589 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 281 |
logger.error("Visualization failed: %s (Input: %s)", str(e), json_input[:100] + "..." if len(json_input) > 100 else json_input)
|
| 282 |
return (create_empty_figure("Log Probabilities of Generated Tokens"), None, "No finite log probabilities to display.", create_empty_figure("Top Token Log Probabilities"), create_empty_figure("Significant Probability Drops"), 1, 0)
|
| 283 |
|
| 284 |
+
# Analysis functions for detecting correct vs. incorrect traces (unchanged)
|
| 285 |
def analyze_confidence_signature(logprobs, tokens):
|
| 286 |
if not logprobs or not tokens:
|
| 287 |
return "No data for confidence signature analysis.", None
|
|
|
|
| 476 |
return analysis_html, None, None, None, None, None
|
| 477 |
|
| 478 |
# Gradio interface with two tabs: Trace Analysis and Visualization
|
| 479 |
+
try:
|
| 480 |
+
with gr.Blocks(title="Log Probability Visualizer") as app:
|
| 481 |
+
gr.Markdown("# Log Probability Visualizer")
|
| 482 |
+
gr.Markdown(
|
| 483 |
+
"Paste your JSON log prob data below to analyze reasoning traces and visualize tokens in chunks of 100. Fixed filter ≥ -100000, dynamic number of top_logprobs, handles missing or null fields. Next chunk is precomputed proactively."
|
| 484 |
+
)
|
| 485 |
|
| 486 |
+
with gr.Tabs():
|
| 487 |
+
with gr.Tab("Trace Analysis"):
|
| 488 |
+
with gr.Row():
|
| 489 |
+
json_input_analysis = gr.Textbox(
|
| 490 |
+
label="JSON Input for Trace Analysis",
|
| 491 |
+
lines=10,
|
| 492 |
+
placeholder="Paste your JSON (e.g., {\"content\": [{\"bytes\": [44], \"logprob\": 0.0, \"token\": \",\", \"top_logprobs\": {\" so\": -13.8046875, \".\": -13.8046875, \",\": -13.640625}}]}).",
|
| 493 |
+
)
|
| 494 |
+
with gr.Row():
|
| 495 |
+
analysis_output = gr.HTML(label="Trace Analysis Results")
|
| 496 |
+
|
| 497 |
+
btn_analyze = gr.Button("Analyze Trace")
|
| 498 |
+
btn_analyze.click(
|
| 499 |
+
fn=analyze_full_trace,
|
| 500 |
+
inputs=[json_input_analysis],
|
| 501 |
+
outputs=[analysis_output, gr.State(), gr.State(), gr.State(), gr.State(), gr.State()],
|
| 502 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 503 |
|
| 504 |
+
with gr.Tab("Visualization"):
|
| 505 |
+
with gr.Row():
|
| 506 |
+
json_input_viz = gr.Textbox(
|
| 507 |
+
label="JSON Input for Visualization",
|
| 508 |
+
lines=10,
|
| 509 |
+
placeholder="Paste your JSON (e.g., {\"content\": [{\"bytes\": [44], \"logprob\": 0.0, \"token\": \",\", \"top_logprobs\": {\" so\": -13.8046875, \".\": -13.8046875, \",\": -13.640625}}]}).",
|
| 510 |
+
)
|
| 511 |
+
chunk = gr.Number(value=0, label="Current Chunk", precision=0, minimum=0)
|
| 512 |
+
|
| 513 |
+
with gr.Row():
|
| 514 |
+
plot_output = gr.Plot(label="Log Probability Plot (Click for Tokens)")
|
| 515 |
+
drops_output = gr.Plot(label="Probability Drops (Click for Details)")
|
| 516 |
+
|
| 517 |
+
with gr.Row():
|
| 518 |
+
table_output = gr.Dataframe(label="Token Log Probabilities and Top Alternatives")
|
| 519 |
+
alt_viz_output = gr.Plot(label="Top Token Log Probabilities (Click for Details)")
|
| 520 |
+
|
| 521 |
+
with gr.Row():
|
| 522 |
+
text_output = gr.HTML(label="Colored Text (Confidence Visualization)")
|
| 523 |
+
|
| 524 |
+
with gr.Row():
|
| 525 |
+
prev_btn = gr.Button("Previous Chunk")
|
| 526 |
+
next_btn = gr.Button("Next Chunk")
|
| 527 |
+
total_chunks_output = gr.Number(label="Total Chunks", interactive=False)
|
| 528 |
+
|
| 529 |
+
# Precomputed next chunk state (hidden)
|
| 530 |
+
precomputed_next = gr.State(value=None)
|
| 531 |
+
|
| 532 |
+
btn_viz = gr.Button("Visualize")
|
| 533 |
+
btn_viz.click(
|
| 534 |
+
fn=visualize_logprobs,
|
| 535 |
+
inputs=[json_input_viz, chunk],
|
| 536 |
+
outputs=[plot_output, table_output, text_output, alt_viz_output, drops_output, total_chunks_output, chunk],
|
| 537 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 538 |
|
| 539 |
+
# Precompute next chunk proactively when on current chunk
|
| 540 |
+
async def precompute_next_chunk(json_input, current_chunk, precomputed_next):
|
| 541 |
+
if precomputed_next is not None:
|
| 542 |
+
return precomputed_next # Use cached precomputed chunk if available
|
| 543 |
+
try:
|
| 544 |
+
next_tokens, next_logprobs, next_alternatives = await precompute_chunk(json_input, 100, current_chunk)
|
| 545 |
+
if next_tokens is None or next_logprobs is None or next_alternatives is None:
|
| 546 |
+
return None
|
| 547 |
+
return (next_tokens, next_logprobs, next_alternatives)
|
| 548 |
+
except Exception as e:
|
| 549 |
+
logger.error("Precomputation failed for chunk %d: %s", current_chunk + 1, str(e))
|
| 550 |
+
return None
|
| 551 |
+
|
| 552 |
+
# Update chunk on button clicks
|
| 553 |
+
def update_chunk(json_input, current_chunk, action, precomputed_next=None):
|
| 554 |
+
total_chunks = visualize_logprobs(json_input, 0)[5] # Get total chunks
|
| 555 |
+
if action == "prev" and current_chunk > 0:
|
| 556 |
+
current_chunk -= 1
|
| 557 |
+
elif action == "next" and current_chunk < total_chunks - 1:
|
| 558 |
+
current_chunk += 1
|
| 559 |
+
# If precomputed next chunk exists, use it; otherwise, compute it
|
| 560 |
+
if precomputed_next:
|
| 561 |
+
next_tokens, next_logprobs, next_alternatives = precomputed_next
|
| 562 |
+
if next_tokens and next_logprobs and next_alternatives:
|
| 563 |
+
logger.debug("Using precomputed next chunk for chunk %d", current_chunk)
|
| 564 |
+
return visualize_logprobs(json_input, current_chunk)
|
| 565 |
+
return visualize_logprobs(json_input, current_chunk)
|
| 566 |
+
|
| 567 |
+
prev_btn.click(
|
| 568 |
+
fn=update_chunk,
|
| 569 |
+
inputs=[json_input_viz, chunk, gr.State(value="prev"), precomputed_next],
|
| 570 |
+
outputs=[plot_output, table_output, text_output, alt_viz_output, drops_output, total_chunks_output, chunk],
|
| 571 |
+
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 572 |
|
| 573 |
+
next_btn.click(
|
| 574 |
+
fn=update_chunk,
|
| 575 |
+
inputs=[json_input_viz, chunk, gr.State(value="next"), precomputed_next],
|
| 576 |
+
outputs=[plot_output, table_output, text_output, alt_viz_output, drops_output, total_chunks_output, chunk],
|
| 577 |
+
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 578 |
|
| 579 |
+
# Trigger precomputation when chunk changes (via button clicks or initial load)
|
| 580 |
+
def trigger_precomputation(json_input, current_chunk):
|
| 581 |
+
try:
|
| 582 |
+
asyncio.create_task(precompute_next_chunk(json_input, current_chunk, None))
|
| 583 |
+
except Exception as e:
|
| 584 |
+
logger.error("Precomputation trigger failed: %s", str(e))
|
| 585 |
+
return gr.update(value=current_chunk)
|
| 586 |
+
|
| 587 |
+
# Use a dummy event to trigger precomputation on chunk change (simplified for Gradio)
|
| 588 |
+
chunk.change(
|
| 589 |
+
fn=trigger_precomputation,
|
| 590 |
+
inputs=[json_input_viz, chunk],
|
| 591 |
+
outputs=[chunk],
|
| 592 |
+
)
|
| 593 |
+
except Exception as e:
|
| 594 |
+
logger.error("Application startup failed: %s", str(e))
|
| 595 |
+
raise
|