RFTSystems commited on
Commit
d5fddc3
·
verified ·
1 Parent(s): 387797b

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +72 -15
app.py CHANGED
@@ -1,24 +1,40 @@
1
  import json
2
  import os
3
  import tempfile
4
- from typing import Any, Dict, Optional, Tuple
 
5
 
6
  import gradio as gr
7
 
8
  from drp.bundle import verify_bundle
9
  from drp.diff import diff_bundles
10
  from drp.report import render_report_markdown
 
11
  from drp.simulate import make_demo_bundle_zip, fork_patch_bundle
12
 
13
 
14
  APP_TITLE = "TimelineDiff — Differential Reproducibility Protocol (DRP)"
15
 
16
 
 
 
 
 
17
  def _tmp_path(name: str) -> str:
18
- d = tempfile.mkdtemp(prefix="drp_")
19
  return os.path.join(d, name)
20
 
21
 
 
 
 
 
 
 
 
 
 
 
22
  def ui_verify(bundle_file) -> Tuple[str, Dict[str, Any]]:
23
  if not bundle_file:
24
  return "Upload a bundle zip first.", {"ok": False}
@@ -28,30 +44,52 @@ def ui_verify(bundle_file) -> Tuple[str, Dict[str, Any]]:
28
  return msg, summary
29
 
30
 
31
- def ui_diff(bundle_a, bundle_b) -> Tuple[str, Dict[str, Any], str]:
32
  if not bundle_a or not bundle_b:
33
- return "Upload two bundles.", {"error": "missing input"}, ""
34
 
35
  diff = diff_bundles(bundle_a.name, bundle_b.name)
36
  md = render_report_markdown(diff)
37
 
38
- # export report artifacts
39
- out_zip = _tmp_path("drp-diff-report.zip")
40
- out_md = _tmp_path("report.md")
41
- out_json = _tmp_path("diff.json")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
42
 
43
  with open(out_md, "w", encoding="utf-8") as f:
44
  f.write(md)
45
  with open(out_json, "w", encoding="utf-8") as f:
46
  json.dump(diff, f, ensure_ascii=False, indent=2)
47
 
48
- import zipfile
 
 
 
49
  with zipfile.ZipFile(out_zip, "w", compression=zipfile.ZIP_DEFLATED) as z:
50
  z.write(out_md, arcname="report.md")
 
51
  z.write(out_json, arcname="diff.json")
52
 
53
- headline = " Diff complete."
54
- return headline, diff, out_zip
 
 
55
 
56
 
57
  def ui_generate(seed_a: int, seed_b: int, chaos: float) -> Tuple[str, str, str]:
@@ -89,19 +127,37 @@ def ui_fork(source_bundle, fork_index: int, patch_kind: str, patch_step: str, pa
89
 
90
 
91
  with gr.Blocks(title=APP_TITLE) as demo:
92
- gr.Markdown(f"# {APP_TITLE}\nDiff two agent timelines. Find first divergence. Export a forensic report.")
93
 
94
  with gr.Tab("Diff two bundles"):
95
  with gr.Row():
96
  bundle_a = gr.File(label="Bundle A (.zip)", file_types=[".zip"])
97
  bundle_b = gr.File(label="Bundle B (.zip)", file_types=[".zip"])
 
98
  run = gr.Button("Compute differential report", variant="primary")
99
 
100
  status = gr.Textbox(label="Status", interactive=False)
 
 
 
 
 
 
 
 
 
101
  diff_json = gr.JSON(label="Diff JSON (summary + per-event diffs)")
102
- report_zip = gr.File(label="Download drp-diff-report.zip")
103
 
104
- run.click(fn=ui_diff, inputs=[bundle_a, bundle_b], outputs=[status, diff_json, report_zip])
 
 
 
 
 
 
 
 
 
105
 
106
  with gr.Tab("Verify bundle integrity"):
107
  bundle_v = gr.File(label="Bundle (.zip)", file_types=[".zip"])
@@ -130,6 +186,7 @@ with gr.Blocks(title=APP_TITLE) as demo:
130
  with gr.Row():
131
  patch_kind = gr.Textbox(label="Patch kind (optional)", placeholder="e.g. tool_result")
132
  patch_step = gr.Textbox(label="Patch step (optional)", placeholder="e.g. t12.tool_result")
 
133
  patch_payload = gr.Textbox(
134
  label="Patch payload JSON (optional)",
135
  lines=8,
@@ -142,7 +199,7 @@ with gr.Blocks(title=APP_TITLE) as demo:
142
  fork_btn.click(fn=ui_fork, inputs=[src, fork_index, patch_kind, patch_step, patch_payload], outputs=[fork_msg, fork_file])
143
 
144
  gr.Markdown(
145
- "Tip: In a real agent exporter, emit DRP events at: LLM calls, tool calls/results, memory writes, planner steps, guardrails."
146
  )
147
 
148
  if __name__ == "__main__":
 
1
  import json
2
  import os
3
  import tempfile
4
+ import zipfile
5
+ from typing import Any, Dict, Optional, Tuple, List
6
 
7
  import gradio as gr
8
 
9
  from drp.bundle import verify_bundle
10
  from drp.diff import diff_bundles
11
  from drp.report import render_report_markdown
12
+ from drp.pdf_report import write_pdf_report
13
  from drp.simulate import make_demo_bundle_zip, fork_patch_bundle
14
 
15
 
16
  APP_TITLE = "TimelineDiff — Differential Reproducibility Protocol (DRP)"
17
 
18
 
19
+ def _tmp_dir() -> str:
20
+ return tempfile.mkdtemp(prefix="drp_")
21
+
22
+
23
  def _tmp_path(name: str) -> str:
24
+ d = _tmp_dir()
25
  return os.path.join(d, name)
26
 
27
 
28
+ def _as_alignment_rows(alignment: List[Dict[str, Any]]) -> List[List[Any]]:
29
+ """
30
+ Convert alignment dict rows to Dataframe rows.
31
+ """
32
+ rows = []
33
+ for r in alignment:
34
+ rows.append([r.get("i"), r.get("status"), r.get("kind_a"), r.get("step_a"), r.get("kind_b"), r.get("step_b")])
35
+ return rows
36
+
37
+
38
  def ui_verify(bundle_file) -> Tuple[str, Dict[str, Any]]:
39
  if not bundle_file:
40
  return "Upload a bundle zip first.", {"ok": False}
 
44
  return msg, summary
45
 
46
 
47
+ def ui_diff(bundle_a, bundle_b) -> Tuple[str, str, Dict[str, Any], List[List[Any]], str, str, str]:
48
  if not bundle_a or not bundle_b:
49
+ return "Upload two bundles.", "", {"error": "missing input"}, [], "", "", ""
50
 
51
  diff = diff_bundles(bundle_a.name, bundle_b.name)
52
  md = render_report_markdown(diff)
53
 
54
+ # Summary header (quick context above JSON)
55
+ s = diff.get("summary", {})
56
+ parts = []
57
+ if s.get("first_divergence_index") is None:
58
+ parts.append("Timelines identical")
59
+ else:
60
+ parts.append(f"Identical until step/index {s.get('first_divergence_index')}")
61
+ parts.append(f"{s.get('diff_event_count', 0)} events differ")
62
+ if s.get("missing_event_count", 0):
63
+ parts.append(f"{s.get('missing_event_count')} missing")
64
+ if s.get("final_reward_delta") is not None:
65
+ parts.append(f"Final reward delta: {s.get('final_reward_delta'):.6g}")
66
+ summary_line = " · ".join(parts)
67
+
68
+ # Export artifacts
69
+ out_dir = _tmp_dir()
70
+ out_md = os.path.join(out_dir, "report.md")
71
+ out_json = os.path.join(out_dir, "diff.json")
72
+ out_pdf = os.path.join(out_dir, "report.pdf")
73
+ out_zip = os.path.join(out_dir, "drp-diff-report.zip")
74
 
75
  with open(out_md, "w", encoding="utf-8") as f:
76
  f.write(md)
77
  with open(out_json, "w", encoding="utf-8") as f:
78
  json.dump(diff, f, ensure_ascii=False, indent=2)
79
 
80
+ # PDF: render from markdown lines (plain, reliable)
81
+ md_lines = md.splitlines()
82
+ write_pdf_report(out_pdf, "DRP Differential Report", md_lines)
83
+
84
  with zipfile.ZipFile(out_zip, "w", compression=zipfile.ZIP_DEFLATED) as z:
85
  z.write(out_md, arcname="report.md")
86
+ z.write(out_pdf, arcname="report.pdf")
87
  z.write(out_json, arcname="diff.json")
88
 
89
+ alignment_rows = _as_alignment_rows(diff.get("alignment", []))
90
+
91
+ status = "✅ Diff complete."
92
+ return status, summary_line, diff, alignment_rows, out_zip, out_pdf, out_md
93
 
94
 
95
  def ui_generate(seed_a: int, seed_b: int, chaos: float) -> Tuple[str, str, str]:
 
127
 
128
 
129
  with gr.Blocks(title=APP_TITLE) as demo:
130
+ gr.Markdown(f"# {APP_TITLE}\nDiff two agent timelines. Find first divergence. Export forensic reports.")
131
 
132
  with gr.Tab("Diff two bundles"):
133
  with gr.Row():
134
  bundle_a = gr.File(label="Bundle A (.zip)", file_types=[".zip"])
135
  bundle_b = gr.File(label="Bundle B (.zip)", file_types=[".zip"])
136
+
137
  run = gr.Button("Compute differential report", variant="primary")
138
 
139
  status = gr.Textbox(label="Status", interactive=False)
140
+ summary = gr.Textbox(label="Summary (fast context)", interactive=False)
141
+
142
+ alignment_table = gr.Dataframe(
143
+ headers=["i", "status", "kind_a", "step_a", "kind_b", "step_b"],
144
+ label="Timeline alignment (scan for first divergence)",
145
+ interactive=False,
146
+ wrap=True,
147
+ )
148
+
149
  diff_json = gr.JSON(label="Diff JSON (summary + per-event diffs)")
 
150
 
151
+ with gr.Row():
152
+ report_zip = gr.File(label="Download drp-diff-report.zip (MD + PDF + JSON)")
153
+ report_pdf = gr.File(label="Download report.pdf")
154
+ report_md = gr.File(label="Download report.md")
155
+
156
+ run.click(
157
+ fn=ui_diff,
158
+ inputs=[bundle_a, bundle_b],
159
+ outputs=[status, summary, diff_json, alignment_table, report_zip, report_pdf, report_md],
160
+ )
161
 
162
  with gr.Tab("Verify bundle integrity"):
163
  bundle_v = gr.File(label="Bundle (.zip)", file_types=[".zip"])
 
186
  with gr.Row():
187
  patch_kind = gr.Textbox(label="Patch kind (optional)", placeholder="e.g. tool_result")
188
  patch_step = gr.Textbox(label="Patch step (optional)", placeholder="e.g. t12.tool_result")
189
+
190
  patch_payload = gr.Textbox(
191
  label="Patch payload JSON (optional)",
192
  lines=8,
 
199
  fork_btn.click(fn=ui_fork, inputs=[src, fork_index, patch_kind, patch_step, patch_payload], outputs=[fork_msg, fork_file])
200
 
201
  gr.Markdown(
202
+ "Exporter tip: emit DRP events at LLM calls, tool calls/results, memory writes, planner steps, guardrails, and state snapshots."
203
  )
204
 
205
  if __name__ == "__main__":